PdnBaseForm.cs 28 KB

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