~ubuntu-branches/ubuntu/trusty/monodevelop/trusty-proposed

« back to all changes in this revision

Viewing changes to src/core/Mono.Texteditor/Mono.TextEditor/Gui/GtkWorkarounds.cs

  • Committer: Package Import Robot
  • Author(s): Jo Shields
  • Date: 2013-05-12 09:46:03 UTC
  • mto: This revision was merged to the branch mainline in revision 29.
  • Revision ID: package-import@ubuntu.com-20130512094603-mad323bzcxvmcam0
Tags: upstream-4.0.5+dfsg
ImportĀ upstreamĀ versionĀ 4.0.5+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
61
61
                [DllImport (LIBOBJC, EntryPoint = "objc_msgSend_stret")]
62
62
                static extern void objc_msgSend_RectangleF (out RectangleF rect, IntPtr klass, IntPtr selector);
63
63
                
 
64
                [DllImport ("libgtk-quartz-2.0.dylib")]
 
65
                static extern IntPtr gdk_quartz_window_get_nswindow (IntPtr window);
 
66
 
64
67
                static IntPtr cls_NSScreen;
65
68
                static IntPtr sel_screens, sel_objectEnumerator, sel_nextObject, sel_frame, sel_visibleFrame,
66
 
                        sel_requestUserAttention;
 
69
                        sel_requestUserAttention, sel_setHasShadow, sel_invalidateShadow;
67
70
                static IntPtr sharedApp;
68
71
                static IntPtr cls_NSEvent;
69
72
                static IntPtr sel_modifierFlags;
126
129
                        sel_frame = sel_registerName ("frame");
127
130
                        sel_requestUserAttention = sel_registerName ("requestUserAttention:");
128
131
                        sel_modifierFlags = sel_registerName ("modifierFlags");
 
132
                        sel_setHasShadow = sel_registerName ("setHasShadow:");
 
133
                        sel_invalidateShadow = sel_registerName ("invalidateShadow");
129
134
                        sharedApp = objc_msgSend_IntPtr (objc_getClass ("NSApplication"), sel_registerName ("sharedApplication"));
130
135
                }
131
136
                
184
189
                        int kind = critical?  NSCriticalRequest : NSInformationalRequest;
185
190
                        objc_msgSend_int_int (sharedApp, sel_requestUserAttention, kind);
186
191
                }
 
192
 
 
193
                // Note: we can't reuse RectangleF because the layout is different...
 
194
                [StructLayout (LayoutKind.Sequential)]
 
195
                struct Rect {
 
196
                        public int Left;
 
197
                        public int Top;
 
198
                        public int Right;
 
199
                        public int Bottom;
 
200
 
 
201
                        public int X { get { return Left; } }
 
202
                        public int Y { get { return Top; } }
 
203
                        public int Width { get { return Right - Left; } }
 
204
                        public int Height { get { return Bottom - Top; } }
 
205
                }
 
206
 
 
207
                const int MonitorInfoFlagsPrimary = 0x01;
 
208
 
 
209
                [StructLayout (LayoutKind.Sequential)]
 
210
                unsafe struct MonitorInfo {
 
211
                        public int Size;
 
212
                        public Rect Frame;         // Monitor
 
213
                        public Rect VisibleFrame;  // Work
 
214
                        public int Flags;
 
215
                        public fixed byte Device[32];
 
216
                }
 
217
 
 
218
                [UnmanagedFunctionPointer (CallingConvention.Winapi)]
 
219
                delegate int EnumMonitorsCallback (IntPtr hmonitor, IntPtr hdc, IntPtr prect, IntPtr user_data);
 
220
 
 
221
                [DllImport ("User32.dll")]
 
222
                extern static int EnumDisplayMonitors (IntPtr hdc, IntPtr clip, EnumMonitorsCallback callback, IntPtr user_data);
 
223
 
 
224
                [DllImport ("User32.dll")]
 
225
                extern static int GetMonitorInfoA (IntPtr hmonitor, ref MonitorInfo info);
 
226
 
 
227
                static Gdk.Rectangle WindowsGetUsableMonitorGeometry (Gdk.Screen screen, int monitor_id)
 
228
                {
 
229
                        Gdk.Rectangle geometry = screen.GetMonitorGeometry (monitor_id);
 
230
                        List<MonitorInfo> screens = new List<MonitorInfo> ();
 
231
 
 
232
                        EnumDisplayMonitors (IntPtr.Zero, IntPtr.Zero, delegate (IntPtr hmonitor, IntPtr hdc, IntPtr prect, IntPtr user_data) {
 
233
                                var info = new MonitorInfo ();
 
234
 
 
235
                                unsafe {
 
236
                                        info.Size = sizeof (MonitorInfo);
 
237
                                }
 
238
 
 
239
                                GetMonitorInfoA (hmonitor, ref info);
 
240
 
 
241
                                // In order to keep the order the same as Gtk, we need to put the primary monitor at the beginning.
 
242
                                if ((info.Flags & MonitorInfoFlagsPrimary) != 0)
 
243
                                        screens.Insert (0, info);
 
244
                                else
 
245
                                        screens.Add (info);
 
246
 
 
247
                                return 1;
 
248
                        }, IntPtr.Zero);
 
249
 
 
250
                        MonitorInfo monitor = screens[monitor_id];
 
251
                        Rect visible = monitor.VisibleFrame;
 
252
                        Rect frame = monitor.Frame;
 
253
 
 
254
                        // Rebase the VisibleFrame off of Gtk's idea of this monitor's geometry (since they use different coordinate systems)
 
255
                        int x = geometry.X + (visible.Left - frame.Left);
 
256
                        int width = visible.Width;
 
257
 
 
258
                        int y = geometry.Y + (visible.Top - frame.Top);
 
259
                        int height = visible.Height;
 
260
 
 
261
                        return new Gdk.Rectangle (x, y, width, height);
 
262
                }
187
263
                
188
264
                public static Gdk.Rectangle GetUsableMonitorGeometry (this Gdk.Screen screen, int monitor)
189
265
                {
 
266
                        if (Platform.IsWindows)
 
267
                                return WindowsGetUsableMonitorGeometry (screen, monitor);
 
268
 
190
269
                        if (Platform.IsMac)
191
270
                                return MacGetUsableMonitorGeometry (screen, monitor);
192
271
                        
292
371
                        adj.Value = System.Math.Max (adj.Lower, System.Math.Min (adj.Value + value, adj.Upper - adj.PageSize));
293
372
                }
294
373
                
295
 
                [DllImport (PangoUtil.LIBGTK)]
 
374
                [DllImport (PangoUtil.LIBGTK, CallingConvention = CallingConvention.Cdecl)]
296
375
                extern static bool gdk_event_get_scroll_deltas (IntPtr eventScroll, out double deltaX, out double deltaY);
297
376
                static bool scrollDeltasNotSupported;
298
377
                
317
396
                public static void ShowContextMenu (Gtk.Menu menu, Gtk.Widget parent, Gdk.EventButton evt, Gdk.Rectangle caret)
318
397
                {
319
398
                        Gtk.MenuPositionFunc posFunc = null;
320
 
                        
321
 
                        // NOTE: we don't gtk_menu_attach_to_widget to the parent because it seems to cause issues.
322
 
                        // The expanders in other treeviews in MD stop working when we detach it, and detaching is necessary
323
 
                        // to prevent memory leaks.
324
 
                        // Attaching means menu moves when parent is moved and is destroyed when parent is destroyed. Neither is
325
 
                        // particularly important for us.
326
 
                        // See https://bugzilla.xamarin.com/show_bug.cgi?id=4388
 
399
 
327
400
                        if (parent != null) {
 
401
                                menu.AttachToWidget (parent, null);
 
402
                                menu.Hidden += (sender, e) => {
 
403
                                        menu.Detach ();
 
404
                                };
328
405
                                posFunc = delegate (Gtk.Menu m, out int x, out int y, out bool pushIn) {
329
406
                                        Gdk.Window window = evt != null? evt.Window : parent.GdkWindow;
330
407
                                        window.GetOrigin (out x, out y);
412
489
                }
413
490
                
414
491
                //introduced in GTK 2.20
415
 
                [DllImport (PangoUtil.LIBGDK)]
 
492
                [DllImport (PangoUtil.LIBGDK, CallingConvention = CallingConvention.Cdecl)]
416
493
                extern static bool gdk_keymap_add_virtual_modifiers (IntPtr keymap, ref Gdk.ModifierType state);
417
494
                
418
495
                //Custom patch in Mono Mac w/GTK+ 2.24.8+
419
 
                [DllImport (PangoUtil.LIBGDK)]
 
496
                [DllImport (PangoUtil.LIBGDK, CallingConvention = CallingConvention.Cdecl)]
420
497
                extern static bool gdk_quartz_set_fix_modifiers (bool fix);
421
498
                
422
499
                static Gdk.Keymap keymap = Gdk.Keymap.Default;
529
606
                                        state = (state & ~ctrlAlt) | Gdk.ModifierType.Mod2Mask;
530
607
                                        group = 1;
531
608
                                }
 
609
                                // Case: Caps lock on + shift + key 
 
610
                                // See: Bug 8069 - [UI Refresh] If caps lock is on, holding the shift key prevents typed characters from appearing
 
611
                                if (state.HasFlag (Gdk.ModifierType.ShiftMask)) {
 
612
                                        state &= ~Gdk.ModifierType.ShiftMask;
 
613
                                }
532
614
                        }
533
615
                        
534
616
                        keymap.TranslateKeyboardState (hardware_keycode, state, group, out keyval, out effective_group,
668
750
                {
669
751
                        return rect.Y + rect.Height - 1;
670
752
                }
671
 
                
672
 
                static HashSet<Type> fixedContainerTypes = new HashSet<Type>();
673
 
                static ForallDelegate forallCallback;
 
753
 
 
754
                /// <summary>
 
755
                /// Shows or hides the shadow of the window rendered by the native toolkit
 
756
                /// </summary>
 
757
                public static void ShowNativeShadow (Gtk.Window window, bool show)
 
758
                {
 
759
                        if (Platform.IsMac) {
 
760
                                var ptr = gdk_quartz_window_get_nswindow (window.GdkWindow.Handle);
 
761
                                objc_msgSend_void_bool (ptr, sel_setHasShadow, show);
 
762
                        }
 
763
                }
 
764
 
 
765
                public static void UpdateNativeShadow (Gtk.Window window)
 
766
                {
 
767
                        if (!Platform.IsMac)
 
768
                                return;
 
769
 
 
770
                        var ptr = gdk_quartz_window_get_nswindow (window.GdkWindow.Handle);
 
771
                        objc_msgSend_IntPtr (ptr, sel_invalidateShadow);
 
772
                }
 
773
 
 
774
                [DllImport ("gtksharpglue-2", CallingConvention = CallingConvention.Cdecl)]
 
775
                static extern void gtksharp_container_leak_fixed_marker ();
 
776
 
 
777
                static HashSet<Type> fixedContainerTypes;
 
778
                static Dictionary<IntPtr,ForallDelegate> forallCallbacks;
 
779
                static bool containerLeakFixed;
674
780
                
675
781
                // Works around BXC #3801 - Managed Container subclasses are incorrectly resurrected, then leak.
676
782
                // It does this by registering an alternative callback for gtksharp_container_override_forall, which
678
784
                // finalized->release->dispose->re-wrap resurrection cycle.
679
785
                // We use a dynamic method to access internal/private GTK# API in a performant way without having to track
680
786
                // per-instance delegates.
681
 
                public static void FixContainerLeak<T> (T c)
682
 
                {
683
 
                        var t = typeof (T);
684
 
                        if (fixedContainerTypes.Add (t)) {
685
 
                                if (forallCallback == null) {
686
 
                                        forallCallback = CreateForallCallback ();
 
787
                public static void FixContainerLeak (Gtk.Container c)
 
788
                {
 
789
                        if (containerLeakFixed) {
 
790
                                return;
 
791
                        }
 
792
 
 
793
                        FixContainerLeak (c.GetType ());
 
794
                }
 
795
 
 
796
                static void FixContainerLeak (Type t)
 
797
                {
 
798
                        if (containerLeakFixed) {
 
799
                                return;
 
800
                        }
 
801
 
 
802
                        if (fixedContainerTypes == null) {
 
803
                                try {
 
804
                                        gtksharp_container_leak_fixed_marker ();
 
805
                                        containerLeakFixed = true;
 
806
                                        return;
 
807
                                } catch (EntryPointNotFoundException) {
687
808
                                }
688
 
                                var gt = (GLib.GType) t.GetMethod ("LookupGType", BindingFlags.Instance | BindingFlags.NonPublic).Invoke (c, null);
689
 
                                gtksharp_container_override_forall (gt.Val, forallCallback);
690
 
                        }
 
809
                                fixedContainerTypes = new HashSet<Type>();
 
810
                                forallCallbacks = new Dictionary<IntPtr, ForallDelegate> ();
 
811
                        }
 
812
 
 
813
                        if (!fixedContainerTypes.Add (t)) {
 
814
                                return;
 
815
                        }
 
816
 
 
817
                        //need to fix the callback for the type and all the managed supertypes
 
818
                        var lookupGType = typeof (GLib.Object).GetMethod ("LookupGType", BindingFlags.Static | BindingFlags.NonPublic);
 
819
                        do {
 
820
                                var gt = (GLib.GType) lookupGType.Invoke (null, new[] { t });
 
821
                                var cb = CreateForallCallback (gt.Val);
 
822
                                forallCallbacks[gt.Val] = cb;
 
823
                                gtksharp_container_override_forall (gt.Val, cb);
 
824
                                t = t.BaseType;
 
825
                        } while (fixedContainerTypes.Add (t) && t.Assembly != typeof (Gtk.Container).Assembly);
691
826
                }
692
 
                
693
 
                static ForallDelegate CreateForallCallback ()
 
827
 
 
828
                static ForallDelegate CreateForallCallback (IntPtr gtype)
694
829
                {
695
830
                        var dm = new DynamicMethod (
696
831
                                "ContainerForallCallback",
697
 
                                typeof (void),
698
 
                                new Type[] { typeof (IntPtr), typeof (bool), typeof (IntPtr), typeof (IntPtr) },
699
 
                                typeof (GtkWorkarounds).Module,
 
832
                                typeof(void),
 
833
                                new Type[] { typeof(IntPtr), typeof(bool), typeof(IntPtr), typeof(IntPtr) },
 
834
                                typeof(GtkWorkarounds).Module,
700
835
                                true);
701
836
                        
702
 
                        var invokerType = typeof (Gtk.Container.CallbackInvoker);
 
837
                        var invokerType = typeof(Gtk.Container.CallbackInvoker);
703
838
                        
704
839
                        //this was based on compiling a similar method and disassembling it
705
840
                        ILGenerator il = dm.GetILGenerator ();
706
841
                        var IL_002b = il.DefineLabel ();
707
842
                        var IL_003f = il.DefineLabel ();
708
843
                        var IL_0060 = il.DefineLabel ();
709
 
                        var IL_0072 = il.DefineLabel ();
710
 
                        
711
 
                        var loc_container  = il.DeclareLocal (typeof (Gtk.Container));
712
 
                        var loc_obj = il.DeclareLocal (typeof (object));
 
844
                        var label_return = il.DefineLabel ();
 
845
 
 
846
                        var loc_container = il.DeclareLocal (typeof(Gtk.Container));
 
847
                        var loc_obj = il.DeclareLocal (typeof(object));
713
848
                        var loc_invoker = il.DeclareLocal (invokerType);
714
 
                        var loc_ex = il.DeclareLocal (typeof (Exception));
715
 
                        
 
849
                        var loc_ex = il.DeclareLocal (typeof(Exception));
 
850
 
 
851
                        //check that the type is an exact match
 
852
                        // prevent stack overflow, because the callback on a more derived type will handle everything
 
853
                        il.Emit (OpCodes.Ldarg_0);
 
854
                        il.Emit (OpCodes.Call, typeof(GLib.ObjectManager).GetMethod ("gtksharp_get_type_id", BindingFlags.Static | BindingFlags.NonPublic));
 
855
 
 
856
                        il.Emit (OpCodes.Ldc_I8, gtype.ToInt64 ());
 
857
                        il.Emit (OpCodes.Newobj, typeof (IntPtr).GetConstructor (new Type[] { typeof (Int64) }));
 
858
                        il.Emit (OpCodes.Call, typeof (IntPtr).GetMethod ("op_Equality", BindingFlags.Static | BindingFlags.Public));
 
859
                        il.Emit (OpCodes.Brfalse, label_return);
 
860
 
716
861
                        il.BeginExceptionBlock ();
717
862
                        il.Emit (OpCodes.Ldnull);
718
863
                        il.Emit (OpCodes.Stloc, loc_container);
723
868
                        il.Emit (OpCodes.Stloc, loc_obj);
724
869
                        il.Emit (OpCodes.Ldloc, loc_obj);
725
870
                        il.Emit (OpCodes.Brfalse, IL_002b);
726
 
                        
 
871
 
727
872
                        var tref = typeof (GLib.Object).Assembly.GetType ("GLib.ToggleRef");
728
873
                        il.Emit (OpCodes.Ldloc, loc_obj);
729
874
                        il.Emit (OpCodes.Castclass, tref);
766
911
                        il.Emit (OpCodes.Ldloc, loc_ex);
767
912
                        il.Emit (OpCodes.Ldc_I4_0);
768
913
                        il.Emit (OpCodes.Call, typeof (GLib.ExceptionManager).GetMethod ("RaiseUnhandledException"));
769
 
                        il.Emit (OpCodes.Leave, IL_0072);
 
914
                        il.Emit (OpCodes.Leave, label_return);
770
915
                        il.EndExceptionBlock ();
771
916
                        
772
 
                        il.MarkLabel (IL_0072);
 
917
                        il.MarkLabel (label_return);
773
918
                        il.Emit (OpCodes.Ret);
774
919
                        
775
920
                        return (ForallDelegate) dm.CreateDelegate (typeof (ForallDelegate));
776
921
                }
777
922
                
778
 
                [GLib.CDeclCallback]
 
923
                [UnmanagedFunctionPointer (CallingConvention.Cdecl)]
779
924
                delegate void ForallDelegate (IntPtr container, bool include_internals, IntPtr cb, IntPtr data);
780
925
                
781
 
                [DllImport("gtksharpglue-2", CallingConvention=CallingConvention.Cdecl)]
 
926
                [DllImport("gtksharpglue-2", CallingConvention = CallingConvention.Cdecl)]
782
927
                static extern void gtksharp_container_override_forall (IntPtr gtype, ForallDelegate cb);
783
928
 
784
929
                public static string MarkupLinks (string text)
785
930
                {
786
 
                        if (Mono.TextEditor.GtkWorkarounds.GtkMinorVersion < 18)
 
931
                        if (GtkMinorVersion < 18)
787
932
                                return text;
788
933
                        return HighlightUrlSemanticRule.UrlRegex.Replace (text, MatchToUrl);
789
934
                }
796
941
 
797
942
                public static void SetLinkHandler (this Gtk.Label label, Action<string> urlHandler)
798
943
                {
799
 
                        if (Mono.TextEditor.GtkWorkarounds.GtkMinorVersion >= 18)
 
944
                        if (GtkMinorVersion >= 18)
800
945
                                new UrlHandlerClosure (urlHandler).ConnectTo (label);
801
946
                }
802
947