configure.in, AssemblyInfo.cs: For those unfortunate earthlings without libchm, libwv...
[beagle.git] / search / Tray / NotificationArea.cs
blobd9e4ca3dc05b2b53af963be419d6775b4ba38386
1 //
2 // NotificationAreaIcon.cs
3 //
4 // Copyright (C) 2005 Todd Berman <tberman@off.net>
5 // Copyright (C) 2005 Ed Catmur <ed@catmur.co.uk>
6 // Copyright (C) 2005 Novell, Inc. (Miguel de Icaza, Aaron Bockover)
7 //
9 // NOTE: throughout IntPtr is used for the Xlib long type, as this tends to
10 // have the correct width and does not require any configure checks.
12 using System;
13 using System.Runtime.InteropServices;
15 using Gtk;
16 using Gdk;
18 namespace Search.Tray {
20 public class NotificationArea : Plug
22 private uint stamp;
23 private Orientation orientation;
25 private IntPtr selection_atom;
26 private IntPtr manager_atom;
27 private IntPtr system_tray_opcode_atom;
28 private IntPtr orientation_atom;
29 private IntPtr message_data_atom;
30 private IntPtr manager_window;
31 private FilterFunc filter;
33 public NotificationArea (string name)
35 Title = name;
36 Init ();
39 public NotificationArea (string name, Gdk.Screen screen)
41 Title = name;
42 Screen = screen;
43 Init ();
46 [DllImport ("libc.so.6")]
47 private static extern IntPtr memcpy (ref XClientMessageEvent.DataUnion dest, IntPtr src, IntPtr len);
49 public uint SendMessage (uint timeout, string message)
51 if (manager_window == IntPtr.Zero) {
52 return 0;
55 byte[] arr = System.Text.Encoding.UTF8.GetBytes (message);
56 IntPtr unmanaged_arr = Marshal.AllocHGlobal (arr.Length);
57 Marshal.Copy (arr, 0, unmanaged_arr, arr.Length);
59 SendManagerMessage (SystemTrayMessage.BeginMessage, (IntPtr) Id, timeout, (uint) arr.Length, ++stamp);
61 gdk_error_trap_push ();
63 for (int index = 0; index < message.Length; index += 20) {
64 XClientMessageEvent ev = new XClientMessageEvent ();
66 IntPtr display = gdk_x11_display_get_xdisplay (Display.Handle);
68 ev.type = XEventName.ClientMessage;
69 ev.window = (IntPtr) Id;
70 ev.format = 8;
71 ev.message_type = message_data_atom;
73 int len = Math.Min (arr.Length - index, 20);
74 memcpy (ref ev.data, (IntPtr)((int)unmanaged_arr + index), (IntPtr)len);
76 XSendEvent (display, manager_window, false, (IntPtr) EventMask.StructureNotifyMask, ref ev);
77 XSync (display, false);
80 gdk_error_trap_pop ();
82 return stamp;
85 public void CancelMessage (uint id)
87 if (id == 0) {
88 return;
91 SendManagerMessage (SystemTrayMessage.CancelMessage, (IntPtr) Id, id, 0, 0);
94 private void Init ()
96 stamp = 1;
97 orientation = Orientation.Horizontal;
98 AddEvents ((int)EventMask.PropertyChangeMask);
99 filter = new FilterFunc (ManagerFilter);
102 [GLib.ConnectBefore]
103 private void TransparentExposeEvent (object obj, Gtk.ExposeEventArgs args)
105 Gtk.Widget widget = (Gtk.Widget)obj;
106 Gdk.Rectangle area = args.Event.Area;
108 widget.GdkWindow.ClearArea (area.X, area.Y, area.Width, area.Height);
111 private void MakeTransparentAgain (object obj, Gtk.StyleSetArgs args)
113 Gtk.Widget widget = (Gtk.Widget)obj;
115 widget.GdkWindow.SetBackPixmap (null, true);
118 private void MakeTransparent (object obj, EventArgs args)
120 Gtk.Widget widget = (Gtk.Widget)obj;
121 if (widget.IsNoWindow || widget.IsAppPaintable)
122 return;
124 widget.AppPaintable = true;
125 widget.DoubleBuffered = false;
126 widget.GdkWindow.SetBackPixmap (null, true);
127 widget.ExposeEvent += TransparentExposeEvent;
128 widget.StyleSet += MakeTransparentAgain;
131 protected override void OnRealized ()
133 base.OnRealized ();
134 MakeTransparent (this, EventArgs.Empty);
135 Display display = Screen.Display;
136 IntPtr xdisplay = gdk_x11_display_get_xdisplay (display.Handle);
137 selection_atom = XInternAtom (xdisplay, "_NET_SYSTEM_TRAY_S" + Screen.Number.ToString (), false);
138 manager_atom = XInternAtom (xdisplay, "MANAGER", false);
139 system_tray_opcode_atom = XInternAtom (xdisplay, "_NET_SYSTEM_TRAY_OPCODE", false);
140 orientation_atom = XInternAtom (xdisplay, "_NET_SYSTEM_TRAY_ORIENTATION", false);
141 message_data_atom = XInternAtom (xdisplay, "_NET_SYSTEM_TRAY_MESSAGE_DATA", false);
142 UpdateManagerWindow (false);
143 SendDockRequest ();
144 Screen.RootWindow.AddFilter (filter);
147 protected override void OnAdded (Gtk.Widget child)
149 child.Realized += MakeTransparent;
150 base.OnAdded (child);
153 protected override void OnUnrealized ()
155 if (manager_window != IntPtr.Zero) {
156 Gdk.Window gdkwin = Gdk.Window.ForeignNewForDisplay (Display, (uint)manager_window);
157 if (gdkwin != null) {
158 gdkwin.RemoveFilter (filter);
162 Screen.RootWindow.RemoveFilter (filter);
163 base.OnUnrealized ();
166 private void UpdateManagerWindow (bool dock_if_realized)
168 IntPtr xdisplay = gdk_x11_display_get_xdisplay (Display.Handle);
170 if (manager_window != IntPtr.Zero) {
171 return;
174 XGrabServer (xdisplay);
176 manager_window = XGetSelectionOwner (xdisplay, selection_atom);
177 if (manager_window != IntPtr.Zero) {
178 XSelectInput (xdisplay, manager_window, (IntPtr) (EventMask.StructureNotifyMask | EventMask.PropertyChangeMask));
181 XUngrabServer (xdisplay);
182 XFlush (xdisplay);
184 if (manager_window != IntPtr.Zero) {
185 Gdk.Window gdkwin = Gdk.Window.ForeignNewForDisplay (Display, (uint)manager_window);
186 if (gdkwin != null) {
187 gdkwin.AddFilter (filter);
190 if (dock_if_realized && IsRealized) {
191 SendDockRequest ();
194 GetOrientationProperty ();
198 private void SendDockRequest ()
200 SendManagerMessage (SystemTrayMessage.RequestDock, manager_window, Id, 0, 0);
203 private void SendManagerMessage (SystemTrayMessage message, IntPtr window, uint data1, uint data2, uint data3)
205 XClientMessageEvent ev = new XClientMessageEvent ();
206 IntPtr display;
208 ev.type = XEventName.ClientMessage;
209 ev.window = window;
210 ev.message_type = system_tray_opcode_atom;
211 ev.format = 32;
212 ev.data.ptr1 = (IntPtr)gdk_x11_get_server_time (GdkWindow.Handle);
213 ev.data.ptr2 = (IntPtr)message;
214 ev.data.ptr3 = (IntPtr)data1;
215 ev.data.ptr4 = (IntPtr)data2;
216 ev.data.ptr5 = (IntPtr)data3;
218 display = gdk_x11_display_get_xdisplay (Display.Handle);
219 gdk_error_trap_push ();
220 XSendEvent (display, manager_window, false, (IntPtr) EventMask.NoEventMask, ref ev);
221 XSync (display, false);
222 gdk_error_trap_pop ();
225 private FilterReturn ManagerFilter (IntPtr xevent, Event evnt)
227 XAnyEvent xev = (XAnyEvent) Marshal.PtrToStructure (xevent, typeof(XAnyEvent));
229 if (xev.type == XEventName.ClientMessage){
230 XClientMessageEvent xclient = (XClientMessageEvent) Marshal.PtrToStructure (xevent, typeof(XClientMessageEvent));
232 if (xclient.message_type == manager_atom && xclient.data.ptr2 == selection_atom) {
233 UpdateManagerWindow (true);
234 return FilterReturn.Continue;
238 if (xev.window == manager_window) {
239 if (xev.type == XEventName.PropertyNotify){
240 XPropertyEvent xproperty = (XPropertyEvent) Marshal.PtrToStructure (xevent, typeof(XPropertyEvent));
241 if (xproperty.atom == orientation_atom) {
242 GetOrientationProperty();
243 return FilterReturn.Continue;
247 if (xev.type == XEventName.DestroyNotify) {
248 ManagerWindowDestroyed();
252 return FilterReturn.Continue;
255 private void ManagerWindowDestroyed ()
257 if (manager_window != IntPtr.Zero) {
258 Gdk.Window gdkwin = Gdk.Window.ForeignNewForDisplay (Display, (uint) manager_window);
260 if (gdkwin != null) {
261 gdkwin.RemoveFilter (filter);
264 manager_window = IntPtr.Zero;
265 UpdateManagerWindow (true);
269 private void GetOrientationProperty ()
271 IntPtr display;
272 IntPtr type;
273 int format;
274 IntPtr prop_return;
275 IntPtr nitems, bytes_after;
276 int error, result;
278 if (manager_window == IntPtr.Zero) {
279 return;
282 display = gdk_x11_display_get_xdisplay (Display.Handle);
284 gdk_error_trap_push ();
285 type = IntPtr.Zero;
287 result = XGetWindowProperty (display, manager_window, orientation_atom, (IntPtr) 0,
288 (IntPtr) System.Int32.MaxValue, false, (IntPtr) XAtom.Cardinal, out type, out format,
289 out nitems, out bytes_after, out prop_return);
291 error = gdk_error_trap_pop ();
293 if (error != 0 || result != 0) {
294 return;
297 if (type == (IntPtr) XAtom.Cardinal) {
298 orientation = ((SystemTrayOrientation) Marshal.ReadInt32 (prop_return) == SystemTrayOrientation.Horz)
299 ? Orientation.Horizontal
300 : Orientation.Vertical;
301 if (OrientationChanged != null)
302 OrientationChanged (this, orientation);
305 if (prop_return != IntPtr.Zero) {
306 XFree (prop_return);
310 public Orientation Orientation {
311 get {
312 return orientation;
316 public delegate void OrientationChangedHandler (NotificationArea area, Orientation orientation);
317 public event OrientationChangedHandler OrientationChanged;
319 [DllImport ("libgdk-x11-2.0.so.0")]
320 private static extern IntPtr gdk_x11_display_get_xdisplay (IntPtr display);
322 [DllImport ("libgdk-x11-2.0.so.0")]
323 private static extern int gdk_x11_get_server_time (IntPtr window);
325 [DllImport ("libgdk-x11-2.0.so.0")]
326 private static extern void gdk_error_trap_push ();
328 [DllImport ("libgdk-x11-2.0.so.0")]
329 private static extern int gdk_error_trap_pop ();
331 [DllImport ("libX11.so.6")]
332 private extern static IntPtr XInternAtom(IntPtr display, string atom_name, bool only_if_exists);
334 [DllImport ("libX11.so.6")]
335 private extern static void XGrabServer (IntPtr display);
337 [DllImport ("libX11.so.6")]
338 private extern static void XUngrabServer (IntPtr display);
340 [DllImport ("libX11.so.6")]
341 private extern static int XFlush (IntPtr display);
343 [DllImport ("libX11.so.6")]
344 private extern static int XSync (IntPtr display, bool discard);
346 [DllImport ("libX11.so.6")]
347 private extern static int XFree (IntPtr display);
349 [DllImport ("libX11.so.6")]
350 private extern static IntPtr XGetSelectionOwner (IntPtr display, IntPtr atom);
352 [DllImport ("libX11.so.6")]
353 private extern static IntPtr XSelectInput (IntPtr display, IntPtr window, IntPtr mask);
355 [DllImport ("libX11.so.6")]
356 private extern static int XSendEvent(IntPtr display, IntPtr window, bool propagate, IntPtr event_mask,
357 ref XClientMessageEvent send_event);
359 [DllImport("libX11.so.6")]
360 private extern static int XGetWindowProperty(IntPtr display, IntPtr w, IntPtr property, IntPtr long_offset,
361 IntPtr long_length, bool deleteProp, IntPtr req_type,
362 out IntPtr actual_type_return, out int actual_format_return,
363 out IntPtr nitems_return, out IntPtr bytes_after_return,
364 out IntPtr prop_return);
366 [Flags]
367 private enum EventMask {
368 NoEventMask = 0,
369 KeyPressMask = 1 << 0,
370 KeyReleaseMask = 1 << 1,
371 ButtonPressMask = 1 << 2,
372 ButtonReleaseMask = 1 << 3,
373 EnterWindowMask = 1 << 4,
374 LeaveWindowMask = 1 << 5,
375 PointerMotionMask = 1 << 6,
376 PointerMotionHintMask = 1 << 7,
377 Button1MotionMask = 1 << 8,
378 Button2MotionMask = 1 << 9,
379 Button3MotionMask = 1 << 10,
380 Button4MotionMask = 1 << 11,
381 Button5MotionMask = 1 << 12,
382 ButtonMotionMask = 1 << 13,
383 KeymapStateMask = 1 << 14,
384 ExposureMask = 1 << 15,
385 VisibilityChangeMask = 1 << 16,
386 StructureNotifyMask = 1 << 17,
387 ResizeRedirectMask = 1 << 18,
388 SubstructureNotifyMask = 1 << 19,
389 SubstructureRedirectMask = 1 << 20,
390 FocusChangeMask = 1 << 21,
391 PropertyChangeMask = 1 << 22,
392 ColormapChangeMask = 1 << 23,
393 OwnerGrabButtonMask = 1 << 24
396 private enum SystemTrayMessage {
397 RequestDock = 0,
398 BeginMessage = 1,
399 CancelMessage = 2
402 private enum SystemTrayOrientation {
403 Horz = 0,
404 Vert = 1
407 private enum XEventName {
408 KeyPress = 2,
409 KeyRelease = 3,
410 ButtonPress = 4,
411 ButtonRelease = 5,
412 MotionNotify = 6,
413 EnterNotify = 7,
414 LeaveNotify = 8,
415 FocusIn = 9,
416 FocusOut = 10,
417 KeymapNotify = 11,
418 Expose = 12,
419 GraphicsExpose = 13,
420 NoExpose = 14,
421 VisibilityNotify = 15,
422 CreateNotify = 16,
423 DestroyNotify = 17,
424 UnmapNotify = 18,
425 MapNotify = 19,
426 MapRequest = 20,
427 ReparentNotify = 21,
428 ConfigureNotify = 22,
429 ConfigureRequest = 23,
430 GravityNotify = 24,
431 ResizeRequest = 25,
432 CirculateNotify = 26,
433 CirculateRequest = 27,
434 PropertyNotify = 28,
435 SelectionClear = 29,
436 SelectionRequest = 30,
437 SelectionNotify = 31,
438 ColormapNotify = 32,
439 ClientMessage = 33,
440 MappingNotify = 34,
441 TimerNotify = 100,
442 LASTEvent
445 private enum XAtom {
446 Cardinal = 6,
447 LASTAtom
450 [StructLayout(LayoutKind.Sequential)]
451 private struct XAnyEvent
453 internal XEventName type;
454 internal IntPtr serial;
455 internal bool send_event;
456 internal IntPtr display;
457 internal IntPtr window;
460 [StructLayout(LayoutKind.Sequential)]
461 private struct XPropertyEvent
463 internal XEventName type;
464 internal IntPtr serial;
465 internal bool send_event;
466 internal IntPtr display;
467 internal IntPtr window;
468 internal IntPtr atom;
469 internal IntPtr time;
470 internal int state;
473 [StructLayout(LayoutKind.Sequential)]
474 private struct XClientMessageEvent
476 internal XEventName type;
477 internal IntPtr serial;
478 internal bool send_event;
479 internal IntPtr display;
480 internal IntPtr window;
481 internal IntPtr message_type;
482 internal int format;
484 [StructLayout(LayoutKind.Sequential)]
485 internal struct DataUnion
487 internal IntPtr ptr1;
488 internal IntPtr ptr2;
489 internal IntPtr ptr3;
490 internal IntPtr ptr4;
491 internal IntPtr ptr5;
494 internal DataUnion data;