| 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
 | namespace DBus {
  
  using System;
  using System.Runtime.InteropServices;
  using System.Diagnostics;
  
  public class Message {
    public Message (string name,
                    string dest_service) {
      // the assignment bumps the refcount
      raw = dbus_message_new (name, dest_service);
      if (raw == IntPtr.Zero)
        throw new OutOfMemoryException ();
      dbus_message_unref (raw);
    }
    public string Name {
      get {
        return dbus_message_get_name (raw);
      }
    }
    public static Message Wrap (IntPtr ptr) {
      IntPtr gch_ptr;
      
      gch_ptr = dbus_message_get_data (ptr, wrapper_slot);
      if (gch_ptr != IntPtr.Zero) {
        return (DBus.Message) ((GCHandle)gch_ptr).Target;
      } else {
        return new Message (ptr);
      }
    }
    // surely there's a convention for this pattern with the property
    // and the real member
    IntPtr raw_;
    internal IntPtr raw {
      get {
        return raw_; 
      }
      set {
        if (value == raw_)
          return;
        
        if (raw_ != IntPtr.Zero) {
          IntPtr gch_ptr;
          
          gch_ptr = dbus_message_get_data (raw_,
                                           wrapper_slot);
          Debug.Assert (gch_ptr != IntPtr.Zero);
          dbus_message_set_data (raw_, wrapper_slot,
                                 IntPtr.Zero, IntPtr.Zero);
          
          ((GCHandle) gch_ptr).Free ();
          
          dbus_message_unref (raw_);
        }
        
        raw_ = value;
        if (raw_ != IntPtr.Zero) {
          GCHandle gch;
          dbus_message_ref (raw_);
          // We store a weak reference to the C# object on the C object
          gch = GCHandle.Alloc (this, GCHandleType.WeakTrackResurrection);
          
          dbus_message_set_data (raw_, wrapper_slot,
                                 (IntPtr) gch, IntPtr.Zero);
        }
      }
    }
    ~Message () {
      raw = IntPtr.Zero; // free the native object
    }
    
    Message (IntPtr r) {
      raw = r;
    }
    
    // static constructor runs before any methods 
    static Message () {
      DBus.Internals.Init ();
      
      Debug.Assert (wrapper_slot == -1);
      
      if (!dbus_message_allocate_data_slot (ref wrapper_slot))
        throw new OutOfMemoryException ();
      Debug.Assert (wrapper_slot >= 0);
    }
    // slot used to store the C# object on the C object
    static int wrapper_slot = -1;
    
    [DllImport (DBus.Internals.DBusLibname, EntryPoint="dbus_message_new")]
      private extern static IntPtr dbus_message_new (string name,
                                                     string dest_service);
    [DllImport (DBus.Internals.DBusLibname, EntryPoint="dbus_message_unref")]
      private extern static void dbus_message_unref (IntPtr ptr);
    [DllImport (DBus.Internals.DBusLibname, EntryPoint="dbus_message_ref")]
      private extern static void dbus_message_ref (IntPtr ptr);
    [DllImport (DBus.Internals.DBusLibname, EntryPoint="dbus_message_get_name")]
      private extern static string dbus_message_get_name (IntPtr ptr);
    [DllImport (DBus.Internals.DBusLibname, EntryPoint="dbus_message_allocate_data_slot")]
      private extern static bool dbus_message_allocate_data_slot (ref int slot);
    [DllImport (DBus.Internals.DBusLibname, EntryPoint="dbus_message_free_data_slot")]
      private extern static void dbus_message_free_data_slot (ref int slot);
    [DllImport (DBus.Internals.DBusLibname, EntryPoint="dbus_message_set_data")]
      private extern static bool dbus_message_set_data (IntPtr ptr,
                                                        int    slot,
                                                        IntPtr data,
                                                        IntPtr free_data_func);
    [DllImport (DBus.Internals.DBusLibname, EntryPoint="dbus_message_get_data")]
      private extern static IntPtr dbus_message_get_data (IntPtr ptr,
                                                          int    slot);
  }
}
 |