diff options
author | Jose Medrano <josmed@microsoft.com> | 2019-06-26 15:56:20 +0300 |
---|---|---|
committer | monojenkins <jo.shields+jenkins@xamarin.com> | 2019-07-03 20:26:16 +0300 |
commit | 0a07503bfeacde3f92fabf7156effc3942148fb6 (patch) | |
tree | e5ba2467dcd146ebc1f4b24ddb1124f5393817e1 /main | |
parent | 5b135742da1ecd7a7f9dbe0e0faf9b8b160c93e6 (diff) |
Adds a ZOrder system based in GtkNSViewHost This commits fixes the current problem with the zorder in adding views to the GtkQuartz window. Because this, we where having some problems in drag and drop and clicking over views. To fix this we added a new mechanism to order the position of the views, and fix if there are other views not well calculated. Fixed VSTS #935567 - [Shell] Mouse click and resize in Splitters sometimes fails to complete the operation
Diffstat (limited to 'main')
9 files changed, 144 insertions, 38 deletions
diff --git a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport.Toolbox/NativeViews/ClickedButton.cs b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport.Toolbox/NativeViews/ClickedButton.cs index 6ee0f8eb2a..4d580cfa91 100644 --- a/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport.Toolbox/NativeViews/ClickedButton.cs +++ b/main/src/addins/MonoDevelop.DesignerSupport/MonoDevelop.DesignerSupport.Toolbox/NativeViews/ClickedButton.cs @@ -55,29 +55,29 @@ namespace MonoDevelop.DesignerSupport.Toolbox.NativeViews return base.BecomeFirstResponder (); } - #region INativeChildView
+ #region INativeChildView - public void OnKeyPressed (object o, Gtk.KeyPressEventArgs ev)
- {
+ public void OnKeyPressed (object o, Gtk.KeyPressEventArgs ev) + { if (ev.Event.State == Gdk.ModifierType.None && (ev.Event.Key == Gdk.Key.KP_Enter || ev.Event.Key == Gdk.Key.KP_Space)) { PerformClick (this); - }
- }
-
- public void OnKeyReleased (object o, Gtk.KeyReleaseEventArgs ev)
- {
-
+ } } - public override void KeyDown (NSEvent theEvent)
- {
- base.KeyDown (theEvent);
- if ((int)theEvent.ModifierFlags == (int)KeyModifierFlag.None && (theEvent.KeyCode == (int)KeyCodes.Enter || theEvent.KeyCode == (int)KeyCodes.Space)) {
- PerformClick (this);
- }
+ public void OnKeyReleased (object o, Gtk.KeyReleaseEventArgs ev) + { + + } + + public override void KeyDown (NSEvent theEvent) + { + base.KeyDown (theEvent); + if ((int)theEvent.ModifierFlags == (int)KeyModifierFlag.None && (theEvent.KeyCode == (int)KeyCodes.Enter || theEvent.KeyCode == (int)KeyCodes.Space)) { + PerformClick (this); + } } - #endregion
+ #endregion } } #endif
\ No newline at end of file diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/DockContainer.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/DockContainer.cs index 2dd13f38f1..00173c9d43 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/DockContainer.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/DockContainer.cs @@ -161,16 +161,18 @@ namespace MonoDevelop.Components.Docking int usedSplitters; + const int SplitterSize = 5; + internal void AllocateSplitter (DockGroup grp, int index, Gdk.Rectangle a) { var s = splitters[usedSplitters++]; if (a.Height > a.Width) { - a.Width = 5; - a.X -= 2; + a.Width = SplitterSize; + a.X -= (int)(SplitterSize / 2); } else { - a.Height = 5; - a.Y -= 2; + a.Height = SplitterSize; + a.Y -= (int)(SplitterSize / 2); } s.SizeAllocate (a); s.Init (grp, index); diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/SplitterMacHostWidget.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/SplitterMacHostWidget.cs index f0859dea41..4f6cd550eb 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/SplitterMacHostWidget.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/SplitterMacHostWidget.cs @@ -42,7 +42,7 @@ namespace MonoDevelop.Components.Docking public SplitterMacHostWidget () { view = new MacSplitterWidget (); - host = new GtkNSViewHost (view, AppKit.NSWindowOrderingMode.Above); + host = new GtkNSViewHost (view); } public Widget Parent => host.Parent; diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/HPanedThin.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/HPanedThin.cs index d7dce73991..8cfe8e8990 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/HPanedThin.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/HPanedThin.cs @@ -160,7 +160,7 @@ namespace MonoDevelop.Components horizontal = parent is HPanedThin; handle = new MacPanedHandleView (parent); - host = new Gtk.GtkNSViewHost (handle, NSWindowOrderingMode.Above); + host = new Gtk.GtkNSViewHost (handle); GrabAreaSize = HandleGrabWidth; diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/Mac/DragEventTrapView.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/Mac/DragEventTrapView.cs index f57f6fd6c5..ce2e77bf37 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/Mac/DragEventTrapView.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/Mac/DragEventTrapView.cs @@ -49,8 +49,11 @@ namespace MonoDevelop.Components.Mac /// NOTE: this view should be added with NSWindowOrderingMode.Above to its superview, to /// make sure the it's the first widget to receive pointer events. /// </remarks> - abstract class DragEventTrapView : NSView + abstract class DragEventTrapView : NSView, Gtk.INSViewOrdering { + const int DefaultSplitterZOrder = 1000; + public int ZOrder => DefaultSplitterZOrder; + NSCursor currentCursor; bool hover, dragging; @@ -99,6 +102,7 @@ namespace MonoDevelop.Components.Mac public override void MouseEntered (NSEvent theEvent) { + AddGdkEventFilter (); lastEventTimestamp = theEvent.Timestamp; if (!dragging) { SetDragCursor (); @@ -112,6 +116,7 @@ namespace MonoDevelop.Components.Mac lastEventTimestamp = theEvent.Timestamp; if (!dragging) { SetDefaultCursor (); + RemoveGdkEventFilter (); } hover = false; base.MouseExited (theEvent); @@ -130,8 +135,6 @@ namespace MonoDevelop.Components.Mac { lastEventTimestamp = theEvent.Timestamp; dragging = true; - - AddGdkEventFilter (); } public override void MouseUp (NSEvent theEvent) diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/Mac/GtkNSViewHost.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/Mac/GtkNSViewHost.cs index be3c2cdf5a..17999656f8 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/Mac/GtkNSViewHost.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/Mac/GtkNSViewHost.cs @@ -24,13 +24,25 @@ using System; using System.Diagnostics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; - using AppKit; using CoreGraphics; using ObjCRuntime; +using Foundation; namespace Gtk { + /// <summary> + /// This interface helps to reorganize the ZOrder of a native view inside a GdkQuarz window + /// </summary> + public interface INSViewOrdering + { + /// <summary> + /// This parameter is taking into account when this viewhost is added. + /// More values means the view is on top of others + /// </summary> + public int ZOrder { get; } + } + public sealed class GtkNSViewHost : Widget { const string LIBGTKQUARTZ = "libgtk-quartz-2.0.dylib"; @@ -67,7 +79,6 @@ namespace Gtk NSView view; NSView superview; bool sizeAllocated; - NSWindowOrderingMode? zOrder; public GtkNSViewHost (NSView view) { @@ -76,11 +87,6 @@ namespace Gtk WidgetFlags |= WidgetFlags.NoWindow; } - public GtkNSViewHost (NSView view, NSWindowOrderingMode position) : this (view) - { - zOrder = position; - } - void UpdateViewFrame () { LogEnter (); @@ -147,6 +153,20 @@ namespace Gtk } } + NSComparisonResult CompareViews (NSView view1, NSView view2) + { + if (view1 is INSViewOrdering viewOrdering1) { + + if (view2 is INSViewOrdering viewOrdering2 && viewOrdering2.ZOrder >= viewOrdering1.ZOrder) + return NSComparisonResult.Ascending; + //view 1 on top + return NSComparisonResult.Descending; + + } + //if view1 is not ordering view 2 on top + return NSComparisonResult.Ascending; + } + protected override void OnRealized () { LogEnter (); @@ -157,15 +177,12 @@ namespace Gtk var superviewHandle = gdk_quartz_window_get_nsview (GdkWindow.Handle); if (superviewHandle != IntPtr.Zero) superview = Runtime.GetNSObject<NSView> (superviewHandle); - } + } if (superview != null && view != null) { - if (zOrder.HasValue) - superview.AddSubview (view, zOrder.Value, null); - else - superview.AddSubview (view); + superview.AddSubview (view); + superview.SortSubviews (CompareViews); } - base.OnRealized (); UpdateViewFrame (); diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/Mac/Messaging.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/Mac/Messaging.cs index fecd358c0f..a22c65271e 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/Mac/Messaging.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/Mac/Messaging.cs @@ -61,6 +61,9 @@ namespace MonoDevelop.Components.Mac [DllImport (LIBOBJC_DYLIB, EntryPoint="objc_msgSend")] public static extern uint UInt32_objc_msgSend (IntPtr receiver, IntPtr selector); + + [DllImport (LIBOBJC_DYLIB, EntryPoint = "objc_msgSend")] + public extern static void void_objc_msgSend_IntPtr_IntPtr (IntPtr receiver, IntPtr selector, IntPtr arg1, IntPtr arg2); } } #endif diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/Mac/NSViewExtensions.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/Mac/NSViewExtensions.cs new file mode 100644 index 0000000000..9d7e89b4cc --- /dev/null +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/Mac/NSViewExtensions.cs @@ -0,0 +1,80 @@ +// +// Author: +// Rolf Kvinge <rolf@xamarin.com> +// +// Copyright (c) Microsoft Corp. (https://www.microsoft.com) +// +// 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 +// AUTHORS OR COPYRIGHT HOLDERS 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. + +using System; +using System.Runtime.InteropServices; +using Foundation; +using ObjCRuntime; + +namespace AppKit +{ + public static class NSViewExtensions + { + delegate nint view_compare_func (IntPtr view1, IntPtr view2, IntPtr context); + static view_compare_func view_comparer = view_compare; + + sealed class SortData + { + public Exception Exception; + public Func<NSView, NSView, NSComparisonResult> Comparer; + } + + [MonoPInvokeCallback (typeof (view_compare_func))] + static nint view_compare (IntPtr view1, IntPtr view2, IntPtr context) + { + var data = (SortData)GCHandle.FromIntPtr (context).Target; + try { + var a = (NSView)Runtime.GetNSObject (view1); + var b = (NSView)Runtime.GetNSObject (view2); + return (nint)(long)data.Comparer (a, b); + } catch (Exception e) { + data.Exception = e; + return (nint)(long)NSComparisonResult.Same; + } + } + + public static void SortSubviews (this NSView view, Func<NSView, NSView, NSComparisonResult> comparer) + { + if (comparer == null) + throw new ArgumentNullException (nameof (comparer)); + + var func = Marshal.GetFunctionPointerForDelegate (view_comparer); + var context = new SortData () { Comparer = comparer }; + var handle = GCHandle.Alloc (context); + try { + SortSubviews (view, func, GCHandle.ToIntPtr (handle)); + if (context.Exception != null) + throw new Exception ($"An exception occurred during sorting.", context.Exception); + } finally { + handle.Free (); + } + } + + static readonly IntPtr sel_sortSubviewsUsingFunction_context_ = Selector.GetHandle ("sortSubviewsUsingFunction:context:"); + static void SortSubviews (NSView view, IntPtr function_pointer, IntPtr context) + { + MonoDevelop.Components.Mac.Messaging.void_objc_msgSend_IntPtr_IntPtr (view.Handle, sel_sortSubviewsUsingFunction_context_, function_pointer, context); + } + } +} diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.csproj b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.csproj index 35329ccb92..4314bb4e98 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.csproj +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.csproj @@ -4252,6 +4252,7 @@ <Compile Include="MonoDevelop.Components.Docking\SplitterMacHostWidget.cs" /> <Compile Include="MonoDevelop.Components\Mac\DragEventTrapView.cs" /> <Compile Include="MonoDevelop.Components\Mac\NativeToolkitHelper.cs" /> + <Compile Include="MonoDevelop.Components\Mac\NSViewExtensions.cs" /> </ItemGroup> <ItemGroup Condition="'$(Configuration)' == 'DebugMac' OR '$(Configuration)' == 'ReleaseMac'"> <Compile Include="MonoDevelop.Components\Mac\KeyCodes.cs" /> |