2023-01-24 15:29:31 +01:00
|
|
|
|
/* Copyright (c) Cloud Software Group, Inc.
|
2013-06-24 13:41:48 +02:00
|
|
|
|
*
|
|
|
|
|
* Redistribution and use in source and binary forms,
|
|
|
|
|
* with or without modification, are permitted provided
|
|
|
|
|
* that the following conditions are met:
|
|
|
|
|
*
|
|
|
|
|
* * Redistributions of source code must retain the above
|
|
|
|
|
* copyright notice, this list of conditions and the
|
|
|
|
|
* following disclaimer.
|
|
|
|
|
* * Redistributions in binary form must reproduce the above
|
|
|
|
|
* copyright notice, this list of conditions and the
|
|
|
|
|
* following disclaimer in the documentation and/or other
|
|
|
|
|
* materials provided with the distribution.
|
|
|
|
|
*
|
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
|
|
|
|
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
|
|
|
|
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
|
|
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
|
|
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
|
|
|
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
|
|
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
|
|
|
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
|
|
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
|
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
|
|
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
|
|
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
|
|
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
|
|
|
* SUCH DAMAGE.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
using System;
|
|
|
|
|
using System.ComponentModel;
|
|
|
|
|
using System.Drawing;
|
|
|
|
|
using System.Windows.Forms;
|
|
|
|
|
using XenAPI;
|
|
|
|
|
using XenAdmin.Core;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace XenAdmin.ConsoleView
|
|
|
|
|
{
|
|
|
|
|
public partial class VNCView : UserControl
|
|
|
|
|
{
|
|
|
|
|
private readonly VM source;
|
2016-07-05 00:05:51 +02:00
|
|
|
|
private readonly VNCTabView vncTabView;
|
2022-02-02 12:13:14 +01:00
|
|
|
|
public Form undockedForm;
|
2013-06-24 13:41:48 +02:00
|
|
|
|
|
2017-02-27 19:00:46 +01:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Helper boolean to only trigger Resize_End when window is really resized by dragging edges
|
|
|
|
|
/// Without this Resize_End is triggered even when window is moved around and not resized
|
|
|
|
|
/// </summary>
|
2022-02-02 12:13:14 +01:00
|
|
|
|
private bool undockedFormResized;
|
2017-02-27 19:00:46 +01:00
|
|
|
|
|
2022-02-02 12:13:14 +01:00
|
|
|
|
public bool IsDocked => undockedForm == null || !undockedForm.Visible;
|
2013-06-24 13:41:48 +02:00
|
|
|
|
|
|
|
|
|
public void Pause()
|
|
|
|
|
{
|
2022-02-02 12:13:14 +01:00
|
|
|
|
vncTabView?.Pause();
|
2013-06-24 13:41:48 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void Unpause()
|
|
|
|
|
{
|
2022-02-02 12:13:14 +01:00
|
|
|
|
vncTabView?.Unpause();
|
2013-06-24 13:41:48 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public VNCView(VM source, string elevatedUsername, string elevatedPassword)
|
|
|
|
|
{
|
|
|
|
|
Program.AssertOnEventThread();
|
|
|
|
|
|
|
|
|
|
this.source = source;
|
2016-07-03 19:54:54 +02:00
|
|
|
|
this.vncTabView = new VNCTabView(this, source, elevatedUsername, elevatedPassword) {Dock = DockStyle.Fill};
|
2013-06-24 13:41:48 +02:00
|
|
|
|
|
|
|
|
|
InitializeComponent();
|
|
|
|
|
this.Controls.Add(this.vncTabView);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void UnregisterEventListeners()
|
|
|
|
|
{
|
|
|
|
|
if(source != null)
|
|
|
|
|
source.PropertyChanged -= new PropertyChangedEventHandler(Server_PropertyChanged);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private Size oldUndockedSize = Size.Empty;
|
|
|
|
|
private Point oldUndockedLocation = Point.Empty;
|
|
|
|
|
private bool oldScaledSetting = false;
|
|
|
|
|
|
2015-11-10 14:12:13 +01:00
|
|
|
|
public void DockUnDock()
|
2013-06-24 13:41:48 +02:00
|
|
|
|
{
|
2022-02-02 12:13:14 +01:00
|
|
|
|
if (IsDocked)
|
2013-06-24 13:41:48 +02:00
|
|
|
|
{
|
|
|
|
|
if (this.undockedForm == null)
|
|
|
|
|
{
|
|
|
|
|
undockedForm = new Form();
|
|
|
|
|
undockedForm.Text = UndockedWindowTitle(source);
|
|
|
|
|
source.PropertyChanged -= Server_PropertyChanged;
|
|
|
|
|
source.PropertyChanged += Server_PropertyChanged;
|
|
|
|
|
undockedForm.Icon = Program.MainWindow.Icon;
|
|
|
|
|
undockedForm.FormClosing += new FormClosingEventHandler(delegate(object sender, FormClosingEventArgs e)
|
|
|
|
|
{
|
2015-11-10 14:12:13 +01:00
|
|
|
|
this.DockUnDock();
|
2013-06-24 13:41:48 +02:00
|
|
|
|
});
|
|
|
|
|
undockedForm.StartPosition = FormStartPosition.CenterScreen;
|
2017-02-27 19:00:46 +01:00
|
|
|
|
FormWindowState lastState = undockedForm.WindowState;
|
2013-06-24 13:41:48 +02:00
|
|
|
|
undockedForm.Resize += new EventHandler(
|
|
|
|
|
delegate(Object o, EventArgs a)
|
|
|
|
|
{
|
2017-02-27 19:00:46 +01:00
|
|
|
|
undockedFormResized = true;
|
|
|
|
|
if (undockedForm.WindowState != lastState && undockedForm.WindowState != FormWindowState.Minimized)
|
|
|
|
|
{
|
|
|
|
|
lastState = undockedForm.WindowState;
|
|
|
|
|
UpdateRDPResolution();
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-24 13:41:48 +02:00
|
|
|
|
if (undockedForm.WindowState == FormWindowState.Minimized)
|
|
|
|
|
{
|
|
|
|
|
vncTabView.Pause();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
vncTabView.Unpause();
|
|
|
|
|
}
|
|
|
|
|
});
|
2017-02-27 19:00:46 +01:00
|
|
|
|
|
|
|
|
|
undockedForm.ResizeEnd += new EventHandler(
|
|
|
|
|
delegate(Object o, EventArgs a)
|
|
|
|
|
{
|
|
|
|
|
if (undockedFormResized)
|
|
|
|
|
UpdateRDPResolution();
|
|
|
|
|
undockedFormResized = false;
|
|
|
|
|
});
|
|
|
|
|
|
2013-06-24 13:41:48 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this.Controls.Remove(vncTabView);
|
|
|
|
|
undockedForm.Controls.Add(vncTabView);
|
|
|
|
|
|
2016-07-05 00:05:51 +02:00
|
|
|
|
oldScaledSetting = vncTabView.IsScaled;
|
2013-06-24 13:41:48 +02:00
|
|
|
|
|
2016-07-08 10:19:39 +02:00
|
|
|
|
vncTabView.showHeaderBar(!source.is_control_domain, true);
|
2013-06-24 13:41:48 +02:00
|
|
|
|
|
|
|
|
|
undockedForm.ClientSize = vncTabView.GrowToFit();
|
|
|
|
|
|
2015-11-10 14:12:13 +01:00
|
|
|
|
if (oldUndockedSize != Size.Empty
|
2013-06-24 13:41:48 +02:00
|
|
|
|
&& oldUndockedLocation != Point.Empty
|
|
|
|
|
&& HelpersGUI.WindowIsOnScreen(oldUndockedLocation, oldUndockedSize))
|
|
|
|
|
{
|
|
|
|
|
undockedForm.Size = oldUndockedSize;
|
|
|
|
|
undockedForm.StartPosition = FormStartPosition.Manual;
|
|
|
|
|
undockedForm.Location = oldUndockedLocation;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
undockedForm.HelpButton = true;
|
|
|
|
|
undockedForm.HelpButtonClicked += undockedForm_HelpButtonClicked;
|
|
|
|
|
undockedForm.HelpRequested += undockedForm_HelpRequested;
|
|
|
|
|
|
|
|
|
|
undockedForm.Show();
|
|
|
|
|
|
2015-11-10 14:12:13 +01:00
|
|
|
|
if(Properties.Settings.Default.PreserveScaleWhenUndocked)
|
2016-07-05 00:05:51 +02:00
|
|
|
|
vncTabView.IsScaled = oldScaledSetting;
|
2013-06-24 13:41:48 +02:00
|
|
|
|
|
|
|
|
|
this.reattachConsoleButton.Show();
|
|
|
|
|
this.findConsoleButton.Show();
|
|
|
|
|
}
|
2015-11-10 14:12:13 +01:00
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
//save location of undock vnc control
|
|
|
|
|
this.oldUndockedLocation = undockedForm.Location;
|
|
|
|
|
this.oldUndockedSize = undockedForm.Size;
|
|
|
|
|
|
|
|
|
|
if (!Properties.Settings.Default.PreserveScaleWhenUndocked)
|
2016-07-05 00:05:51 +02:00
|
|
|
|
vncTabView.IsScaled = oldScaledSetting;
|
2015-11-10 14:12:13 +01:00
|
|
|
|
|
|
|
|
|
this.reattachConsoleButton.Hide();
|
|
|
|
|
this.findConsoleButton.Hide();
|
|
|
|
|
|
|
|
|
|
undockedForm.Hide();
|
|
|
|
|
vncTabView.showHeaderBar(true, false);
|
|
|
|
|
undockedForm.Controls.Remove(vncTabView);
|
|
|
|
|
this.Controls.Add(vncTabView);
|
|
|
|
|
|
|
|
|
|
undockedForm.Dispose();
|
|
|
|
|
undockedForm = null;
|
|
|
|
|
}
|
2013-06-24 13:41:48 +02:00
|
|
|
|
|
|
|
|
|
vncTabView.UpdateDockButton();
|
|
|
|
|
|
|
|
|
|
vncTabView.UpdateParentMinimumSize();
|
|
|
|
|
|
|
|
|
|
//Every time we dock / undock I'm going to force an unpause to make sure we don't ever pause a visible one.
|
|
|
|
|
vncTabView.Unpause();
|
|
|
|
|
vncTabView.focus_vnc();
|
2017-02-27 19:00:46 +01:00
|
|
|
|
|
|
|
|
|
//reconnect RDP with docked/undocked window dimensions
|
|
|
|
|
UpdateRDPResolution();
|
2013-06-24 13:41:48 +02:00
|
|
|
|
}
|
|
|
|
|
|
2021-02-24 16:44:38 +01:00
|
|
|
|
private string UndockedWindowTitle(VM vm)
|
2013-06-24 13:41:48 +02:00
|
|
|
|
{
|
2021-02-24 16:44:38 +01:00
|
|
|
|
if (vm.IsControlDomainZero(out Host host))
|
|
|
|
|
return string.Format(Messages.CONSOLE_HOST, host.Name());
|
2016-07-08 10:19:39 +02:00
|
|
|
|
|
2021-02-24 16:44:38 +01:00
|
|
|
|
if (vm.IsSrDriverDomain(out SR sr))
|
|
|
|
|
return string.Format(Messages.CONSOLE_SR_DRIVER_DOMAIN, sr.Name());
|
|
|
|
|
|
|
|
|
|
return vm.Name();
|
2013-06-24 13:41:48 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void undockedForm_HelpButtonClicked(object sender, CancelEventArgs e)
|
|
|
|
|
{
|
|
|
|
|
Help.HelpManager.Launch("TabPageConsole");
|
|
|
|
|
e.Cancel = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void undockedForm_HelpRequested(object sender, HelpEventArgs hlpevent)
|
|
|
|
|
{
|
|
|
|
|
Help.HelpManager.Launch("TabPageConsole");
|
|
|
|
|
hlpevent.Handled = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Server_PropertyChanged(object sender, PropertyChangedEventArgs e)
|
|
|
|
|
{
|
|
|
|
|
if (e.PropertyName == "name_label" && undockedForm != null)
|
|
|
|
|
{
|
2020-05-31 02:43:56 +02:00
|
|
|
|
undockedForm.Text = UndockedWindowTitle(source);
|
2013-06-24 13:41:48 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void findConsoleButton_Click(object sender, EventArgs e)
|
|
|
|
|
{
|
2022-02-02 12:13:14 +01:00
|
|
|
|
if (!IsDocked)
|
2013-06-24 13:41:48 +02:00
|
|
|
|
undockedForm.BringToFront();
|
|
|
|
|
if (undockedForm.WindowState == FormWindowState.Minimized)
|
|
|
|
|
undockedForm.WindowState = FormWindowState.Normal;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void reattachConsoleButton_Click(object sender, EventArgs e)
|
|
|
|
|
{
|
2015-11-10 14:12:13 +01:00
|
|
|
|
DockUnDock();
|
2013-06-24 13:41:48 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
internal void SendCAD()
|
|
|
|
|
{
|
|
|
|
|
if (this.vncTabView != null)
|
|
|
|
|
this.vncTabView.SendCAD();
|
|
|
|
|
}
|
|
|
|
|
|
2015-11-10 14:12:13 +01:00
|
|
|
|
internal void FocusConsole()
|
2013-06-24 13:41:48 +02:00
|
|
|
|
{
|
|
|
|
|
if (this.vncTabView != null)
|
2015-11-10 14:12:13 +01:00
|
|
|
|
vncTabView.focus_vnc();
|
2013-06-24 13:41:48 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
internal void SwitchIfRequired()
|
|
|
|
|
{
|
|
|
|
|
vncTabView.SwitchIfRequired();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
internal Image Snapshot()
|
|
|
|
|
{
|
|
|
|
|
return vncTabView.Snapshot();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void refreshIsoList()
|
|
|
|
|
{
|
|
|
|
|
vncTabView.setupCD();
|
|
|
|
|
}
|
2013-11-14 13:33:02 +01:00
|
|
|
|
|
2017-02-27 19:00:46 +01:00
|
|
|
|
public void UpdateRDPResolution(bool fullscreen = false)
|
|
|
|
|
{
|
|
|
|
|
vncTabView.UpdateRDPResolution(fullscreen);
|
|
|
|
|
}
|
2013-06-24 13:41:48 +02:00
|
|
|
|
}
|
|
|
|
|
}
|