PageRenderTime 56ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/src/Core/PdnBaseForm.cs

https://bitbucket.org/tcz001/openpdn
C# | 1096 lines | 837 code | 172 blank | 87 comment | 140 complexity | 532461c41d53bda33f7ac1ebea6a0bd8 MD5 | raw file
Possible License(s): Unlicense
  1. /////////////////////////////////////////////////////////////////////////////////
  2. // Paint.NET //
  3. // Copyright (C) dotPDN LLC, Rick Brewster, Tom Jackson, and contributors. //
  4. // Portions Copyright (C) Microsoft Corporation. All Rights Reserved. //
  5. // See src/Resources/Files/License.txt for full licensing and attribution //
  6. // details. //
  7. // . //
  8. /////////////////////////////////////////////////////////////////////////////////
  9. using PaintDotNet.SystemLayer;
  10. using System;
  11. using System.Diagnostics;
  12. using System.Drawing;
  13. using System.Collections;
  14. using System.Collections.Generic;
  15. using System.ComponentModel;
  16. using System.Reflection;
  17. using System.Resources;
  18. using System.Runtime.InteropServices;
  19. using System.Security;
  20. using System.Threading;
  21. using System.Windows.Forms;
  22. namespace PaintDotNet
  23. {
  24. /// <summary>
  25. /// This Form class is used to fix a few bugs in Windows Forms, and to add a few performance
  26. /// enhancements, such as disabling opacity != 1.0 when running in a remote TS/RD session.
  27. /// We derive from this class instead of Windows.Forms.Form directly.
  28. /// </summary>
  29. public class PdnBaseForm
  30. : Form,
  31. ISnapManagerHost
  32. {
  33. static PdnBaseForm()
  34. {
  35. Application.EnterThreadModal += new EventHandler(Application_EnterThreadModal);
  36. Application.LeaveThreadModal += new EventHandler(Application_LeaveThreadModal);
  37. Application_EnterThreadModal(null, EventArgs.Empty);
  38. }
  39. // This set keeps track of forms which cannot be the current modal form.
  40. private static Stack<List<Form>> parentModalForms = new Stack<List<Form>>();
  41. private static bool IsInParentModalForms(Form form)
  42. {
  43. foreach (List<Form> formList in parentModalForms)
  44. {
  45. foreach (Form parentModalForm in formList)
  46. {
  47. if (parentModalForm == form)
  48. {
  49. return true;
  50. }
  51. }
  52. }
  53. return false;
  54. }
  55. private static List<Form> GetAllPeerForms(Form form)
  56. {
  57. if (form == null)
  58. {
  59. return new List<Form>();
  60. }
  61. if (form.Owner != null)
  62. {
  63. return GetAllPeerForms(form.Owner);
  64. }
  65. List<Form> forms = new List<Form>();
  66. forms.Add(form);
  67. forms.AddRange(form.OwnedForms);
  68. return forms;
  69. }
  70. private static void Application_EnterThreadModal(object sender, EventArgs e)
  71. {
  72. Form activeForm = Form.ActiveForm;
  73. List<Form> allPeerForms = GetAllPeerForms(activeForm);
  74. parentModalForms.Push(allPeerForms);
  75. }
  76. private static void Application_LeaveThreadModal(object sender, EventArgs e)
  77. {
  78. parentModalForms.Pop();
  79. }
  80. protected override void OnShown(EventArgs e)
  81. {
  82. isShown = true;
  83. Tracing.LogFeature("ShowDialog(" + GetType().FullName + ")");
  84. base.OnShown(e);
  85. }
  86. public bool IsShown
  87. {
  88. get
  89. {
  90. return this.isShown;
  91. }
  92. }
  93. private bool isShown = false;
  94. private bool enableOpacity = true;
  95. private double ourOpacity = 1.0; // store opacity setting so that when we go from disabled->enabled opacity we can set the correct value
  96. private SnapManager snapManager = null;
  97. private System.ComponentModel.IContainer components;
  98. private bool instanceEnableOpacity = true;
  99. private static bool globalEnableOpacity = true;
  100. private FormEx formEx;
  101. private bool processFormHotKeyMutex = false; // if we're already processing a form hotkey, don't let other hotkeys execute.
  102. private static Dictionary<Keys, Function<bool, Keys>> hotkeyRegistrar = null;
  103. /// <summary>
  104. /// Registers a form-wide hot key, and a callback for when the key is pressed.
  105. /// The callback must be an instance method on a Control. Whatever Form the Control
  106. /// is on will process the hotkey, as long as the Form is derived from PdnBaseForm.
  107. /// </summary>
  108. public static void RegisterFormHotKey(Keys keys, Function<bool, Keys> callback)
  109. {
  110. IComponent targetAsComponent = callback.Target as IComponent;
  111. IHotKeyTarget targetAsHotKeyTarget = callback.Target as IHotKeyTarget;
  112. if (targetAsComponent == null && targetAsHotKeyTarget == null)
  113. {
  114. throw new ArgumentException("target instance must implement IComponent or IHotKeyTarget", "callback");
  115. }
  116. if (hotkeyRegistrar == null)
  117. {
  118. hotkeyRegistrar = new Dictionary<Keys, Function<bool, Keys>>();
  119. }
  120. Function<bool, Keys> theDelegate = null;
  121. if (hotkeyRegistrar.ContainsKey(keys))
  122. {
  123. theDelegate = hotkeyRegistrar[keys];
  124. theDelegate += callback;
  125. hotkeyRegistrar[keys] = theDelegate;
  126. }
  127. else
  128. {
  129. theDelegate = new Function<bool, Keys>(callback);
  130. hotkeyRegistrar.Add(keys, theDelegate);
  131. }
  132. if (targetAsComponent != null)
  133. {
  134. targetAsComponent.Disposed += TargetAsComponent_Disposed;
  135. }
  136. else
  137. {
  138. targetAsHotKeyTarget.Disposed += TargetAsHotKeyTarget_Disposed;
  139. }
  140. }
  141. private bool ShouldProcessHotKey(Keys keys)
  142. {
  143. Keys keyOnly = keys & ~Keys.Modifiers;
  144. if (keyOnly == Keys.Back ||
  145. keyOnly == Keys.Delete ||
  146. keyOnly == Keys.Left ||
  147. keyOnly == Keys.Right ||
  148. keyOnly == Keys.Up ||
  149. keyOnly == Keys.Down ||
  150. keys == (Keys.Control | Keys.A) || // select all
  151. keys == (Keys.Control | Keys.Z) || // undo
  152. keys == (Keys.Control | Keys.Y) || // redo
  153. keys == (Keys.Control | Keys.X) || // cut
  154. keys == (Keys.Control | Keys.C) || // copy
  155. keys == (Keys.Control | Keys.V) || // paste
  156. keys == (Keys.Shift | Keys.Delete) || // cut (left-handed)
  157. keys == (Keys.Control | Keys.Insert) || // copy (left-handed)
  158. keys == (Keys.Shift | Keys.Insert) // paste (left-handed)
  159. )
  160. {
  161. Control focused = Utility.FindFocus();
  162. if (focused is TextBox || focused is ComboBox || focused is UpDownBase)
  163. {
  164. return false;
  165. }
  166. }
  167. return true;
  168. }
  169. private static void TargetAsComponent_Disposed(object sender, EventArgs e)
  170. {
  171. ((IComponent)sender).Disposed -= TargetAsComponent_Disposed;
  172. RemoveDisposedTarget(sender);
  173. }
  174. private static void TargetAsHotKeyTarget_Disposed(object sender, EventArgs e)
  175. {
  176. ((IHotKeyTarget)sender).Disposed -= TargetAsHotKeyTarget_Disposed;
  177. RemoveDisposedTarget(sender);
  178. }
  179. static void RemoveDisposedTarget(object sender)
  180. {
  181. // Control was disposed, but it never unregistered for its hotkeys!
  182. List<Keys> keysList = new List<Keys>(hotkeyRegistrar.Keys);
  183. foreach (Keys keys in keysList)
  184. {
  185. Function<bool, Keys> theMultiDelegate = hotkeyRegistrar[keys];
  186. foreach (Delegate theDelegate in theMultiDelegate.GetInvocationList())
  187. {
  188. if (object.ReferenceEquals(theDelegate.Target, sender))
  189. {
  190. UnregisterFormHotKey(keys, (Function<bool, Keys>)theDelegate);
  191. }
  192. }
  193. }
  194. }
  195. public static void UnregisterFormHotKey(Keys keys, Function<bool, Keys> callback)
  196. {
  197. if (hotkeyRegistrar != null)
  198. {
  199. Function<bool, Keys> theDelegate = hotkeyRegistrar[keys];
  200. theDelegate -= callback;
  201. hotkeyRegistrar[keys] = theDelegate;
  202. IComponent targetAsComponent = callback.Target as IComponent;
  203. if (targetAsComponent != null)
  204. {
  205. targetAsComponent.Disposed -= TargetAsComponent_Disposed;
  206. }
  207. IHotKeyTarget targetAsHotKeyTarget = callback.Target as IHotKeyTarget;
  208. if (targetAsHotKeyTarget != null)
  209. {
  210. targetAsHotKeyTarget.Disposed -= TargetAsHotKeyTarget_Disposed;
  211. }
  212. if (theDelegate.GetInvocationList().Length == 0)
  213. {
  214. hotkeyRegistrar.Remove(keys);
  215. }
  216. if (hotkeyRegistrar.Count == 0)
  217. {
  218. hotkeyRegistrar = null;
  219. }
  220. }
  221. }
  222. public void Flash()
  223. {
  224. UI.FlashForm(this);
  225. }
  226. public void RestoreWindow()
  227. {
  228. if (WindowState == FormWindowState.Minimized)
  229. {
  230. UI.RestoreWindow(this);
  231. }
  232. }
  233. /// <summary>
  234. /// Returns the currently active modal form if the process is in the foreground and is active.
  235. /// </summary>
  236. /// <remarks>
  237. /// If Form.ActiveForm is modeless, we search up the chain of owner forms
  238. /// to find its modeless owner form.
  239. /// </remarks>
  240. public static Form CurrentModalForm
  241. {
  242. get
  243. {
  244. Form theForm = Form.ActiveForm;
  245. while (theForm != null && !theForm.Modal && theForm.Owner != null)
  246. {
  247. theForm = theForm.Owner;
  248. }
  249. return theForm;
  250. }
  251. }
  252. /// <summary>
  253. /// Gets whether the current form is the processes' top level modal form.
  254. /// </summary>
  255. public bool IsCurrentModalForm
  256. {
  257. get
  258. {
  259. if (IsInParentModalForms(this))
  260. {
  261. return false;
  262. }
  263. if (this.ContainsFocus)
  264. {
  265. return true;
  266. }
  267. foreach (Form ownedForm in this.OwnedForms)
  268. {
  269. if (ownedForm.ContainsFocus)
  270. {
  271. return true;
  272. }
  273. }
  274. return (this == CurrentModalForm);
  275. }
  276. }
  277. private bool IsTargetFormActive(object target)
  278. {
  279. Control targetControl = null;
  280. if (targetControl == null)
  281. {
  282. Control asControl = target as Control;
  283. if (asControl != null)
  284. {
  285. targetControl = asControl;
  286. }
  287. }
  288. if (targetControl == null)
  289. {
  290. IFormAssociate asIFormAssociate = target as IFormAssociate;
  291. if (asIFormAssociate != null)
  292. {
  293. targetControl = asIFormAssociate.AssociatedForm;
  294. }
  295. }
  296. // target is not a control, or a type of non-control that we recognize as hosted by a control
  297. if (targetControl == null)
  298. {
  299. return false;
  300. }
  301. Form targetForm = targetControl.FindForm();
  302. // target is not on a form
  303. if (targetForm == null)
  304. {
  305. return false;
  306. }
  307. // is the target on the currently active form?
  308. Form activeModalForm = CurrentModalForm;
  309. if (targetForm == activeModalForm)
  310. {
  311. return true;
  312. }
  313. // Nope.
  314. return false;
  315. }
  316. private static object GetConcreteTarget(object target)
  317. {
  318. Delegate asDelegate = target as Delegate;
  319. if (asDelegate == null)
  320. {
  321. return target;
  322. }
  323. else
  324. {
  325. return GetConcreteTarget(asDelegate.Target);
  326. }
  327. }
  328. private bool ProcessFormHotKey(Keys keyData)
  329. {
  330. bool processed = false;
  331. if (this.processFormHotKeyMutex)
  332. {
  333. processed = true;
  334. }
  335. else
  336. {
  337. this.processFormHotKeyMutex = true;
  338. try
  339. {
  340. if (hotkeyRegistrar != null && hotkeyRegistrar.ContainsKey(keyData))
  341. {
  342. Function<bool, Keys> theDelegate = hotkeyRegistrar[keyData];
  343. Delegate[] invokeList = theDelegate.GetInvocationList();
  344. for (int i = invokeList.Length - 1; i >= 0; --i)
  345. {
  346. Function<bool, Keys> invokeMe = (Function<bool, Keys>)invokeList[i];
  347. object concreteTarget = GetConcreteTarget(invokeMe.Target);
  348. if (IsTargetFormActive(concreteTarget))
  349. {
  350. bool result = invokeMe(keyData);
  351. if (result)
  352. {
  353. // The callback handled the key.
  354. processed = true;
  355. break;
  356. }
  357. }
  358. }
  359. }
  360. }
  361. finally
  362. {
  363. this.processFormHotKeyMutex = false;
  364. }
  365. }
  366. return processed;
  367. }
  368. private void OnProcessCmdKeyRelay(object sender, FormEx.ProcessCmdKeyEventArgs e)
  369. {
  370. bool handled = e.Handled;
  371. if (!handled)
  372. {
  373. handled = ProcessCmdKeyData(e.KeyData);
  374. e.Handled = handled;
  375. }
  376. }
  377. public bool RelayProcessCmdKey(ref Message msg, Keys keyData)
  378. {
  379. return ProcessCmdKeyData(keyData);
  380. }
  381. protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
  382. {
  383. bool processed = ProcessCmdKeyData(keyData);
  384. if (!processed)
  385. {
  386. processed = base.ProcessCmdKey(ref msg, keyData);
  387. }
  388. return processed;
  389. }
  390. private bool ProcessCmdKeyData(Keys keyData)
  391. {
  392. bool shouldHandle = ShouldProcessHotKey(keyData);
  393. if (shouldHandle)
  394. {
  395. bool processed = ProcessFormHotKey(keyData);
  396. return processed;
  397. }
  398. else
  399. {
  400. return false;
  401. }
  402. }
  403. public static void UpdateAllForms()
  404. {
  405. try
  406. {
  407. foreach (Form form in Application.OpenForms)
  408. {
  409. try
  410. {
  411. form.Update();
  412. }
  413. catch (Exception)
  414. {
  415. }
  416. }
  417. }
  418. catch (InvalidOperationException)
  419. {
  420. }
  421. }
  422. protected override void OnHelpRequested(HelpEventArgs hevent)
  423. {
  424. if (!hevent.Handled)
  425. {
  426. Utility.ShowHelp(this);
  427. hevent.Handled = true;
  428. }
  429. base.OnHelpRequested(hevent);
  430. }
  431. public static EventHandler EnableOpacityChanged;
  432. private static void OnEnableOpacityChanged()
  433. {
  434. if (EnableOpacityChanged != null)
  435. {
  436. EnableOpacityChanged(null, EventArgs.Empty);
  437. }
  438. }
  439. public bool EnableInstanceOpacity
  440. {
  441. get
  442. {
  443. return instanceEnableOpacity;
  444. }
  445. set
  446. {
  447. instanceEnableOpacity = value;
  448. this.DecideOpacitySetting();
  449. }
  450. }
  451. /// <summary>
  452. /// Gets or sets a flag that enables or disables opacity for all PdnBaseForm instances.
  453. /// If a particular form's EnableInstanceOpacity property is false, that will override
  454. /// this property being 'true'.
  455. /// </summary>
  456. public static bool EnableOpacity
  457. {
  458. get
  459. {
  460. return globalEnableOpacity;
  461. }
  462. set
  463. {
  464. globalEnableOpacity = value;
  465. OnEnableOpacityChanged();
  466. }
  467. }
  468. /// <summary>
  469. /// Gets or sets the titlebar rendering behavior for when the form is deactivated.
  470. /// </summary>
  471. /// <remarks>
  472. /// If this property is false, the titlebar will be rendered in a different color when the form
  473. /// is inactive as opposed to active. If this property is true, it will always render with the
  474. /// active style. If the whole application is deactivated, the title bar will still be drawn in
  475. /// an inactive state.
  476. /// </remarks>
  477. public bool ForceActiveTitleBar
  478. {
  479. get
  480. {
  481. return this.formEx.ForceActiveTitleBar;
  482. }
  483. set
  484. {
  485. this.formEx.ForceActiveTitleBar = value;
  486. }
  487. }
  488. private ThreadPriority originalPriority;
  489. protected override void OnScroll(ScrollEventArgs se)
  490. {
  491. Thread.CurrentThread.Priority = this.originalPriority;
  492. base.OnScroll(se);
  493. }
  494. public PdnBaseForm()
  495. {
  496. this.originalPriority = Thread.CurrentThread.Priority;
  497. Thread.CurrentThread.Priority = ThreadPriority.AboveNormal;
  498. UI.InitScaling(this);
  499. this.SuspendLayout();
  500. InitializeComponent();
  501. this.formEx = new PaintDotNet.SystemLayer.FormEx(this, new RealParentWndProcDelegate(this.RealWndProc));
  502. this.Controls.Add(this.formEx);
  503. this.formEx.Visible = false;
  504. DecideOpacitySetting();
  505. this.ResumeLayout(false);
  506. this.formEx.ProcessCmdKeyRelay += OnProcessCmdKeyRelay;
  507. }
  508. protected override void OnLoad(EventArgs e)
  509. {
  510. if (!this.DesignMode)
  511. {
  512. LoadResources();
  513. }
  514. base.OnLoad(e);
  515. }
  516. public virtual void LoadResources()
  517. {
  518. if (!this.DesignMode)
  519. {
  520. string stringName = this.Name + ".Localized";
  521. string stringValue = StringsResourceManager.GetString(stringName);
  522. if (stringValue != null)
  523. {
  524. try
  525. {
  526. bool boolValue = bool.Parse(stringValue);
  527. if (boolValue)
  528. {
  529. LoadLocalizedResources();
  530. }
  531. }
  532. catch (Exception)
  533. {
  534. }
  535. }
  536. }
  537. }
  538. protected virtual ResourceManager StringsResourceManager
  539. {
  540. get
  541. {
  542. return PdnResources.Strings;
  543. }
  544. }
  545. private void LoadLocalizedResources()
  546. {
  547. LoadLocalizedResources(this.Name, this);
  548. }
  549. private void ParsePair(string theString, out int x, out int y)
  550. {
  551. string[] split = theString.Split(',');
  552. x = int.Parse(split[0]);
  553. y = int.Parse(split[1]);
  554. }
  555. private void LoadLocalizedResources(string baseName, Control control)
  556. {
  557. // Text
  558. string textStringName = baseName + ".Text";
  559. string textString = this.StringsResourceManager.GetString(textStringName);
  560. if (textString != null)
  561. {
  562. control.Text = textString;
  563. }
  564. // Location
  565. string locationStringName = baseName + ".Location";
  566. string locationString = this.StringsResourceManager.GetString(locationStringName);
  567. if (locationString != null)
  568. {
  569. try
  570. {
  571. int x;
  572. int y;
  573. ParsePair(locationString, out x, out y);
  574. control.Location = new Point(x, y);
  575. }
  576. catch (Exception ex)
  577. {
  578. Tracing.Ping(locationStringName + " is invalid: " + locationString + ", exception: " + ex.ToString());
  579. }
  580. }
  581. // Size
  582. string sizeStringName = baseName + ".Size";
  583. string sizeString = this.StringsResourceManager.GetString(sizeStringName);
  584. if (sizeString != null)
  585. {
  586. try
  587. {
  588. int width;
  589. int height;
  590. ParsePair(sizeString, out width, out height);
  591. control.Size = new Size(width, height);
  592. }
  593. catch (Exception ex)
  594. {
  595. Tracing.Ping(sizeStringName + " is invalid: " + sizeString + ", exception: " + ex.ToString());
  596. }
  597. }
  598. // Recurse
  599. foreach (Control child in control.Controls)
  600. {
  601. if (child.Name == null || child.Name.Length > 0)
  602. {
  603. string newBaseName = baseName + "." + child.Name;
  604. LoadLocalizedResources(newBaseName, child);
  605. }
  606. else
  607. {
  608. Tracing.Ping("Name property not set for an instance of " + child.GetType().Name + " within " + baseName);
  609. }
  610. }
  611. }
  612. protected override void OnClosing(CancelEventArgs e)
  613. {
  614. base.OnClosing(e);
  615. if (!e.Cancel)
  616. {
  617. this.ForceActiveTitleBar = false;
  618. }
  619. }
  620. private void EnableOpacityChangedHandler(object sender, EventArgs e)
  621. {
  622. DecideOpacitySetting();
  623. }
  624. protected override void OnHandleCreated(EventArgs e)
  625. {
  626. base.OnHandleCreated (e);
  627. PdnBaseForm.EnableOpacityChanged += new EventHandler(EnableOpacityChangedHandler);
  628. UserSessions.SessionChanged += new EventHandler(UserSessions_SessionChanged);
  629. DecideOpacitySetting();
  630. }
  631. protected override void OnHandleDestroyed(EventArgs e)
  632. {
  633. base.OnHandleDestroyed(e);
  634. PdnBaseForm.EnableOpacityChanged -= new EventHandler(EnableOpacityChangedHandler);
  635. UserSessions.SessionChanged -= new EventHandler(UserSessions_SessionChanged);
  636. }
  637. /// <summary>
  638. /// Clean up any resources being used.
  639. /// </summary>
  640. protected override void Dispose(bool disposing)
  641. {
  642. if (disposing)
  643. {
  644. if (components != null)
  645. {
  646. components.Dispose();
  647. components = null;
  648. }
  649. }
  650. base.Dispose(disposing);
  651. }
  652. /// <summary>
  653. /// Sets the opacity of the form.
  654. /// </summary>
  655. /// <param name="newOpacity">The new opacity value.</param>
  656. /// <remarks>
  657. /// Depending on the system configuration, this request may be ignored. For example,
  658. /// when running within a Terminal Service (or Remote Desktop) session, opacity will
  659. /// always be set to 1.0 for performance reasons.
  660. /// </remarks>
  661. public new double Opacity
  662. {
  663. get
  664. {
  665. return this.ourOpacity;
  666. }
  667. set
  668. {
  669. if (enableOpacity)
  670. {
  671. // Bypassing Form.Opacity eliminates a "black flickering" that occurs when
  672. // the form transitions from Opacity=1.0 to Opacity != 1.0, or vice versa.
  673. // It appears to be a result of toggling the WS_EX_LAYERED style, or the
  674. // fact that Form.Opacity re-applies visual styles when this value transition
  675. // takes place.
  676. SystemLayer.UI.SetFormOpacity(this, value);
  677. }
  678. this.ourOpacity = value;
  679. }
  680. }
  681. /// <summary>
  682. /// Decides whether or not to have opacity be enabled.
  683. /// </summary>
  684. private void DecideOpacitySetting()
  685. {
  686. if (UserSessions.IsRemote || !PdnBaseForm.globalEnableOpacity || !this.EnableInstanceOpacity)
  687. {
  688. if (this.enableOpacity)
  689. {
  690. try
  691. {
  692. UI.SetFormOpacity(this, 1.0);
  693. }
  694. // This fails in certain odd situations (bug #746), so we just eat the exception.
  695. catch (System.ComponentModel.Win32Exception)
  696. {
  697. }
  698. }
  699. this.enableOpacity = false;
  700. }
  701. else
  702. {
  703. if (!this.enableOpacity)
  704. {
  705. // This fails in certain odd situations (bug #746), so we just eat the exception.
  706. try
  707. {
  708. UI.SetFormOpacity(this, this.ourOpacity);
  709. }
  710. catch (System.ComponentModel.Win32Exception)
  711. {
  712. }
  713. }
  714. this.enableOpacity = true;
  715. }
  716. }
  717. public double ScreenAspect
  718. {
  719. get
  720. {
  721. Rectangle bounds = System.Windows.Forms.Screen.FromControl(this).Bounds;
  722. double aspect = (double)bounds.Width / (double)bounds.Height;
  723. return aspect;
  724. }
  725. }
  726. #region Windows Form Designer generated code
  727. /// <summary>
  728. /// Required method for Designer support - do not modify
  729. /// the contents of this method with the code editor.
  730. /// </summary>
  731. private void InitializeComponent()
  732. {
  733. this.components = new System.ComponentModel.Container();
  734. this.SuspendLayout();
  735. //
  736. // PdnBaseForm
  737. //
  738. this.AutoScaleDimensions = new SizeF(96F, 96F);
  739. this.AutoScaleMode = AutoScaleMode.Dpi;
  740. this.ClientSize = new System.Drawing.Size(291, 270);
  741. this.Name = "PdnBaseForm";
  742. this.StartPosition = System.Windows.Forms.FormStartPosition.Manual;
  743. this.Text = "PdnBaseForm";
  744. this.ResumeLayout(false);
  745. }
  746. #endregion
  747. public event MovingEventHandler Moving;
  748. protected virtual void OnMoving(MovingEventArgs mea)
  749. {
  750. if (Moving != null)
  751. {
  752. Moving(this, mea);
  753. }
  754. }
  755. public event CancelEventHandler QueryEndSession;
  756. protected virtual void OnQueryEndSession(CancelEventArgs e)
  757. {
  758. if (QueryEndSession != null)
  759. {
  760. QueryEndSession(this, e);
  761. }
  762. }
  763. private void UserSessions_SessionChanged(object sender, EventArgs e)
  764. {
  765. this.DecideOpacitySetting();
  766. }
  767. void RealWndProc(ref Message m)
  768. {
  769. OurWndProc(ref m);
  770. }
  771. protected override void WndProc(ref Message m)
  772. {
  773. if (this.formEx == null)
  774. {
  775. base.WndProc(ref m);
  776. }
  777. else if (!this.formEx.HandleParentWndProc(ref m))
  778. {
  779. OurWndProc(ref m);
  780. }
  781. }
  782. private void OurWndProc(ref Message m)
  783. {
  784. switch (m.Msg)
  785. {
  786. case 0x0216: // WM_MOVING
  787. unsafe
  788. {
  789. int *p = (int *)m.LParam;
  790. Rectangle rect = Rectangle.FromLTRB(p[0], p[1], p[2], p[3]);
  791. MovingEventArgs mea = new MovingEventArgs(rect);
  792. OnMoving(mea);
  793. p[0] = mea.Rectangle.Left;
  794. p[1] = mea.Rectangle.Top;
  795. p[2] = mea.Rectangle.Right;
  796. p[3] = mea.Rectangle.Bottom;
  797. m.Result = new IntPtr(1);
  798. }
  799. break;
  800. // WinForms doesn't handle this message correctly and wrongly returns 0 instead of 1.
  801. case 0x0011: // WM_QUERYENDSESSION
  802. CancelEventArgs e = new CancelEventArgs();
  803. OnQueryEndSession(e);
  804. m.Result = e.Cancel ? IntPtr.Zero : new IntPtr(1);
  805. break;
  806. default:
  807. base.WndProc(ref m);
  808. break;
  809. }
  810. }
  811. public SnapManager SnapManager
  812. {
  813. get
  814. {
  815. if (this.snapManager == null)
  816. {
  817. this.snapManager = new SnapManager();
  818. }
  819. return snapManager;
  820. }
  821. }
  822. public Size ClientSizeToWindowSize(Size clientSize)
  823. {
  824. Size baseClientSize = ClientSize;
  825. Size baseWindowSize = Size;
  826. int extraWidth = baseWindowSize.Width - baseClientSize.Width;
  827. int extraHeight = baseWindowSize.Height - baseClientSize.Height;
  828. Size windowSize = new Size(clientSize.Width + extraWidth, clientSize.Height + extraHeight);
  829. return windowSize;
  830. }
  831. public Size WindowSizeToClientSize(Size windowSize)
  832. {
  833. Size baseClientSize = ClientSize;
  834. Size baseWindowSize = Size;
  835. int extraWidth = baseWindowSize.Width - baseClientSize.Width;
  836. int extraHeight = baseWindowSize.Height - baseClientSize.Height;
  837. Size clientSize = new Size(windowSize.Width - extraWidth, windowSize.Height - extraHeight);
  838. return clientSize;
  839. }
  840. public Rectangle ClientBoundsToWindowBounds(Rectangle clientBounds)
  841. {
  842. Rectangle currentBounds = this.Bounds;
  843. Rectangle currentClientBounds = this.RectangleToScreen(ClientRectangle);
  844. Rectangle newWindowBounds = new Rectangle(
  845. clientBounds.Left - (currentClientBounds.Left - currentBounds.Left),
  846. clientBounds.Top - (currentClientBounds.Top - currentBounds.Top),
  847. clientBounds.Width + (currentBounds.Width - currentClientBounds.Width),
  848. clientBounds.Height + (currentBounds.Height - currentClientBounds.Height));
  849. return newWindowBounds;
  850. }
  851. public Rectangle WindowBoundsToClientBounds(Rectangle windowBounds)
  852. {
  853. Rectangle currentBounds = this.Bounds;
  854. Rectangle currentClientBounds = this.RectangleToScreen(ClientRectangle);
  855. Rectangle newClientBounds = new Rectangle(
  856. windowBounds.Left + (currentClientBounds.Left - currentBounds.Left),
  857. windowBounds.Top + (currentClientBounds.Top - currentBounds.Top),
  858. windowBounds.Width - (currentBounds.Width - currentClientBounds.Width),
  859. windowBounds.Height - (currentBounds.Height - currentClientBounds.Height));
  860. return newClientBounds;
  861. }
  862. public void EnsureFormIsOnScreen()
  863. {
  864. if (this.WindowState == FormWindowState.Maximized)
  865. {
  866. return;
  867. }
  868. if (this.WindowState == FormWindowState.Minimized)
  869. {
  870. return;
  871. }
  872. Screen ourScreen;
  873. try
  874. {
  875. ourScreen = Screen.FromControl(this);
  876. }
  877. catch (Exception)
  878. {
  879. ourScreen = null;
  880. }
  881. if (ourScreen == null)
  882. {
  883. ourScreen = Screen.PrimaryScreen;
  884. }
  885. Rectangle currentBounds = Bounds;
  886. Rectangle newBounds = EnsureRectIsOnScreen(ourScreen, currentBounds);
  887. Bounds = newBounds;
  888. }
  889. public static Rectangle EnsureRectIsOnScreen(Screen screen, Rectangle bounds)
  890. {
  891. Rectangle newBounds = bounds;
  892. Rectangle screenBounds = screen.WorkingArea;
  893. // Make sure the bottom and right do not fall off the edge, by moving the bounds
  894. if (newBounds.Right > screenBounds.Right)
  895. {
  896. newBounds.X -= (newBounds.Right - screenBounds.Right);
  897. }
  898. if (newBounds.Bottom > screenBounds.Bottom)
  899. {
  900. newBounds.Y -= (newBounds.Bottom - screenBounds.Bottom);
  901. }
  902. // Make sure the top and left haven't fallen off, by moving
  903. if (newBounds.Left < screenBounds.Left)
  904. {
  905. newBounds.X = screenBounds.Left;
  906. }
  907. if (newBounds.Top < screenBounds.Top)
  908. {
  909. newBounds.Y = screenBounds.Top;
  910. }
  911. // Make sure that we are not too wide / tall, by resizing
  912. if (newBounds.Right > screenBounds.Right)
  913. {
  914. newBounds.Width -= (newBounds.Right - screenBounds.Right);
  915. }
  916. if (newBounds.Bottom > screenBounds.Bottom)
  917. {
  918. newBounds.Height -= (newBounds.Bottom - screenBounds.Bottom);
  919. }
  920. // All done.
  921. return newBounds;
  922. }
  923. }
  924. }