61
61
[DllImport (LIBOBJC, EntryPoint = "objc_msgSend_stret")]
62
62
static extern void objc_msgSend_RectangleF (out RectangleF rect, IntPtr klass, IntPtr selector);
64
[DllImport ("libgtk-quartz-2.0.dylib")]
65
static extern IntPtr gdk_quartz_window_get_nswindow (IntPtr window);
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;
184
189
int kind = critical? NSCriticalRequest : NSInformationalRequest;
185
190
objc_msgSend_int_int (sharedApp, sel_requestUserAttention, kind);
193
// Note: we can't reuse RectangleF because the layout is different...
194
[StructLayout (LayoutKind.Sequential)]
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; } }
207
const int MonitorInfoFlagsPrimary = 0x01;
209
[StructLayout (LayoutKind.Sequential)]
210
unsafe struct MonitorInfo {
212
public Rect Frame; // Monitor
213
public Rect VisibleFrame; // Work
215
public fixed byte Device[32];
218
[UnmanagedFunctionPointer (CallingConvention.Winapi)]
219
delegate int EnumMonitorsCallback (IntPtr hmonitor, IntPtr hdc, IntPtr prect, IntPtr user_data);
221
[DllImport ("User32.dll")]
222
extern static int EnumDisplayMonitors (IntPtr hdc, IntPtr clip, EnumMonitorsCallback callback, IntPtr user_data);
224
[DllImport ("User32.dll")]
225
extern static int GetMonitorInfoA (IntPtr hmonitor, ref MonitorInfo info);
227
static Gdk.Rectangle WindowsGetUsableMonitorGeometry (Gdk.Screen screen, int monitor_id)
229
Gdk.Rectangle geometry = screen.GetMonitorGeometry (monitor_id);
230
List<MonitorInfo> screens = new List<MonitorInfo> ();
232
EnumDisplayMonitors (IntPtr.Zero, IntPtr.Zero, delegate (IntPtr hmonitor, IntPtr hdc, IntPtr prect, IntPtr user_data) {
233
var info = new MonitorInfo ();
236
info.Size = sizeof (MonitorInfo);
239
GetMonitorInfoA (hmonitor, ref info);
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);
250
MonitorInfo monitor = screens[monitor_id];
251
Rect visible = monitor.VisibleFrame;
252
Rect frame = monitor.Frame;
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;
258
int y = geometry.Y + (visible.Top - frame.Top);
259
int height = visible.Height;
261
return new Gdk.Rectangle (x, y, width, height);
188
264
public static Gdk.Rectangle GetUsableMonitorGeometry (this Gdk.Screen screen, int monitor)
266
if (Platform.IsWindows)
267
return WindowsGetUsableMonitorGeometry (screen, monitor);
190
269
if (Platform.IsMac)
191
270
return MacGetUsableMonitorGeometry (screen, monitor);
317
396
public static void ShowContextMenu (Gtk.Menu menu, Gtk.Widget parent, Gdk.EventButton evt, Gdk.Rectangle caret)
319
398
Gtk.MenuPositionFunc posFunc = null;
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
327
400
if (parent != null) {
401
menu.AttachToWidget (parent, null);
402
menu.Hidden += (sender, e) => {
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);
669
751
return rect.Y + rect.Height - 1;
672
static HashSet<Type> fixedContainerTypes = new HashSet<Type>();
673
static ForallDelegate forallCallback;
755
/// Shows or hides the shadow of the window rendered by the native toolkit
757
public static void ShowNativeShadow (Gtk.Window window, bool show)
759
if (Platform.IsMac) {
760
var ptr = gdk_quartz_window_get_nswindow (window.GdkWindow.Handle);
761
objc_msgSend_void_bool (ptr, sel_setHasShadow, show);
765
public static void UpdateNativeShadow (Gtk.Window window)
770
var ptr = gdk_quartz_window_get_nswindow (window.GdkWindow.Handle);
771
objc_msgSend_IntPtr (ptr, sel_invalidateShadow);
774
[DllImport ("gtksharpglue-2", CallingConvention = CallingConvention.Cdecl)]
775
static extern void gtksharp_container_leak_fixed_marker ();
777
static HashSet<Type> fixedContainerTypes;
778
static Dictionary<IntPtr,ForallDelegate> forallCallbacks;
779
static bool containerLeakFixed;
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)
684
if (fixedContainerTypes.Add (t)) {
685
if (forallCallback == null) {
686
forallCallback = CreateForallCallback ();
787
public static void FixContainerLeak (Gtk.Container c)
789
if (containerLeakFixed) {
793
FixContainerLeak (c.GetType ());
796
static void FixContainerLeak (Type t)
798
if (containerLeakFixed) {
802
if (fixedContainerTypes == null) {
804
gtksharp_container_leak_fixed_marker ();
805
containerLeakFixed = true;
807
} catch (EntryPointNotFoundException) {
688
var gt = (GLib.GType) t.GetMethod ("LookupGType", BindingFlags.Instance | BindingFlags.NonPublic).Invoke (c, null);
689
gtksharp_container_override_forall (gt.Val, forallCallback);
809
fixedContainerTypes = new HashSet<Type>();
810
forallCallbacks = new Dictionary<IntPtr, ForallDelegate> ();
813
if (!fixedContainerTypes.Add (t)) {
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);
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);
825
} while (fixedContainerTypes.Add (t) && t.Assembly != typeof (Gtk.Container).Assembly);
693
static ForallDelegate CreateForallCallback ()
828
static ForallDelegate CreateForallCallback (IntPtr gtype)
695
830
var dm = new DynamicMethod (
696
831
"ContainerForallCallback",
698
new Type[] { typeof (IntPtr), typeof (bool), typeof (IntPtr), typeof (IntPtr) },
699
typeof (GtkWorkarounds).Module,
833
new Type[] { typeof(IntPtr), typeof(bool), typeof(IntPtr), typeof(IntPtr) },
834
typeof(GtkWorkarounds).Module,
702
var invokerType = typeof (Gtk.Container.CallbackInvoker);
837
var invokerType = typeof(Gtk.Container.CallbackInvoker);
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 ();
711
var loc_container = il.DeclareLocal (typeof (Gtk.Container));
712
var loc_obj = il.DeclareLocal (typeof (object));
844
var label_return = il.DefineLabel ();
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));
849
var loc_ex = il.DeclareLocal (typeof(Exception));
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));
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);
716
861
il.BeginExceptionBlock ();
717
862
il.Emit (OpCodes.Ldnull);
718
863
il.Emit (OpCodes.Stloc, loc_container);
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 ();
772
il.MarkLabel (IL_0072);
917
il.MarkLabel (label_return);
773
918
il.Emit (OpCodes.Ret);
775
920
return (ForallDelegate) dm.CreateDelegate (typeof (ForallDelegate));
923
[UnmanagedFunctionPointer (CallingConvention.Cdecl)]
779
924
delegate void ForallDelegate (IntPtr container, bool include_internals, IntPtr cb, IntPtr data);
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);
784
929
public static string MarkupLinks (string text)
786
if (Mono.TextEditor.GtkWorkarounds.GtkMinorVersion < 18)
931
if (GtkMinorVersion < 18)
788
933
return HighlightUrlSemanticRule.UrlRegex.Replace (text, MatchToUrl);