[Muine] [PATCH] C# implementations of MessageConnection and VolumeButton
- From: Ross Girshick <ross girshick gmail com>
- To: muine-list gnome org
- Subject: [Muine] [PATCH] C# implementations of MessageConnection and VolumeButton
- Date: Mon, 27 Sep 2004 22:31:55 -0400
Hello,
I've been using muine as a jumping off point for learning C# and mono.
My first task was to implement the MessageConnection class and volume
button in C#. I did this a while ago and was reminding about it after
seeing Bastien Nocera's blog post [1] about various programs still
using his "horror" bacon-message-connection. I suppose that this patch
might be of some value to the project since it reduces the size of the
code base and makes it arguably more maintainable.
I see that one other developer also posted a more complete patch
fixing some GC'd delegates. It would be nice to get that patch
committed so that muine will work with Mono 1.1.1.
Cheers,
Ross Girshick
[1] planet.gnome.org, sept. 27th.
--
"Magic is real, unless declared integer."
Index: libmuine/Makefile.am
===================================================================
RCS file: /cvs/gnome/muine/libmuine/Makefile.am,v
retrieving revision 1.10
diff -r1.10 Makefile.am
51,52d50
< volume-button.c \
< volume-button.h \
55,56d52
< bacon-message-connection.c \
< bacon-message-connection.h \
Index: src/Makefile.am
===================================================================
RCS file: /cvs/gnome/muine/src/Makefile.am,v
retrieving revision 1.36
diff -r1.36 Makefile.am
41,42c41,44
< /r:AmazonSearchService.dll \
< /r:System.Web.Services
---
> -r:AmazonSearchService.dll \
> -r:System.Web.Services \
> -r:Mono.Posix
>
Index: src/MessageConnection.cs
===================================================================
RCS file: /cvs/gnome/muine/src/MessageConnection.cs,v
retrieving revision 1.2
diff -r1.2 MessageConnection.cs
2c2
< * Copyright (C) 2004 Jorn Baayen <jorn nl linux org>
---
> * Copyright (C) 2004 Ross Girshick <ross girshick gmail com>
21c21,25
< using System.Runtime.InteropServices;
---
> using System.Net;
> using System.Net.Sockets;
> using Mono.Posix;
> using System.Text;
> using System.IO;
25c29,34
< private IntPtr conn;
---
> public enum StatusCode {
> OK,
> Retry,
> SocketCreateFailure,
> SocketDeleteFailure
> };
27,28c36,39
< [DllImport ("libmuine")]
< private static extern IntPtr bacon_message_connection_new (string name);
---
> public enum ConnectionType {
> Server,
> Client
> };
30,32c41,47
< public MessageConnection ()
< {
< conn = bacon_message_connection_new ("Muine");
---
> private Socket socket;
>
> private string socket_filename;
> public string SocketFilename {
> get {
> return socket_filename;
> }
35,36c50,55
< [DllImport ("libmuine")]
< private static extern bool bacon_message_connection_get_is_server (IntPtr conn);
---
> private ConnectionType role;
> public ConnectionType Role {
> get {
> return role;
> }
> }
38c57,58
< public bool IsServer {
---
> private StatusCode status;
> public StatusCode Status {
40c60
< return bacon_message_connection_get_is_server (conn);
---
> return status;
44,45c64
< public delegate void MessageReceivedHandler (string message,
< IntPtr user_data);
---
> public delegate void MessageReceivedDelegate (string Message);
47,50c66,71
< [DllImport ("libmuine")]
< private static extern void bacon_message_connection_set_callback (IntPtr conn,
< MessageReceivedHandler callback,
< IntPtr user_data);
---
> private MessageReceivedDelegate message_received_handler;
> public MessageReceivedDelegate MessageReceivedHandler {
> set {
> message_received_handler = value;
> }
> }
52c73,74
< public void SetCallback (MessageReceivedHandler handler)
---
>
> public MessageConnection ()
54c76,121
< bacon_message_connection_set_callback (conn, handler, IntPtr.Zero);
---
> string socket_path;
>
> try {
> socket_path = System.IO.Path.GetTempPath ();
> } catch {
> socket_path = "/tmp";
> }
>
> status = StatusCode.OK;
>
> socket_filename = System.IO.Path.Combine (socket_path, "muine-" + Environment.GetEnvironmentVariable ("USER") + ".socket");
>
> socket = new Socket (AddressFamily.Unix, SocketType.Stream, ProtocolType.IP);
> EndPoint socket_end_point = new UnixEndPoint (socket_filename);
>
> if (File.Exists (socket_filename)) {
> role = ConnectionType.Client;
> try {
> socket.Connect (socket_end_point);
> } catch {
> Console.WriteLine ("Socket already exists, removing.");
> try {
> File.Delete (socket_filename);
> status = StatusCode.Retry;
> } catch {
> status = StatusCode.SocketDeleteFailure;
> }
> }
> } else {
> role = ConnectionType.Server;
>
> try {
> socket.Bind (socket_end_point);
> socket.Listen (5);
> socket.BeginAccept (new AsyncCallback (ListenCallback), socket);
> }
> catch
> {
> status = StatusCode.SocketCreateFailure;
> }
> }
> }
>
> ~ MessageConnection ()
> {
> Close ();
57,58c124,127
< [DllImport ("libmuine")]
< private static extern void bacon_message_connection_send (IntPtr conn, string command);
---
> public int Send (string Message)
> {
> return socket.Send (Encoding.ASCII.GetBytes (Message));
> }
60c129
< public void Send (string command)
---
> public void Close ()
62c131,134
< bacon_message_connection_send (conn, command);
---
> if (role == ConnectionType.Server) {
> Console.WriteLine ("Removing socket file");
> File.Delete (socket_filename);
> }
65,66c137,150
< [DllImport ("libmuine")]
< private static extern void bacon_message_connection_free (IntPtr conn);
---
> private void ListenCallback (IAsyncResult state)
> {
> Socket Client = ((Socket)state.AsyncState).EndAccept (state);
> ((Socket)state.AsyncState).BeginAccept (new AsyncCallback (ListenCallback), state.AsyncState);
> byte[] buf = new byte[1024];
> Client.Receive (buf);
>
> string raw_message = Encoding.ASCII.GetString (buf);
> string message = "";
> foreach (char c in raw_message) {
> if (c == 0x0000)
> break;
> message += c;
> }
68c152,155
< public void Close ()
---
> GLib.Idle.Add (new GLib.IdleHandler (new IdleWork (message_received_handler, message).Run));
> }
>
> internal class IdleWork
70c157,170
< bacon_message_connection_free (conn);
---
> private string message;
> private MessageReceivedDelegate callback;
>
> public IdleWork (MessageReceivedDelegate cb, string msg)
> {
> message = msg;
> callback = cb;
> }
>
> public bool Run ()
> {
> callback (message);
> return false;
> }
Index: src/Muine.cs
===================================================================
RCS file: /cvs/gnome/muine/src/Muine.cs,v
retrieving revision 1.31
diff -r1.31 Muine.cs
60c60,71
< if (!conn.IsServer) {
---
> while (conn.Status == MessageConnection.StatusCode.Retry) {
> conn = new MessageConnection ();
> }
>
> if (conn.Status != MessageConnection.StatusCode.OK) {
> Console.WriteLine ("Error creating MessageConnection: " + conn.Status);
> Environment.Exit (1);
> }
>
> /* An instance already exists. Handle command line args and exit. */
> if (conn.Role == MessageConnection.ConnectionType.Client)
> {
103c114
< conn.SetCallback (new MessageConnection.MessageReceivedHandler (HandleMessageReceived));
---
> conn.MessageReceivedHandler = new MessageConnection.MessageReceivedDelegate (HandleMessageReceived);
105a117
>
170,171c182
< private void HandleMessageReceived (string message,
< IntPtr user_data)
---
> private void HandleMessageReceived (string message)
Index: src/VolumeButton.cs
===================================================================
RCS file: /cvs/gnome/muine/src/VolumeButton.cs,v
retrieving revision 1.4
diff -r1.4 VolumeButton.cs
2c2
< * Copyright (C) 2004 Jorn Baayen <jorn nl linux org>
---
> * Copyright (C) 2004 Ross Girshick <ross girshick gmail com>
20,24d19
< using System;
< using System.Collections;
< using System.Runtime.InteropServices;
<
< using Gtk;
25a21,22
> using Gtk;
> using System;
27c24
< public class VolumeButton : Button
---
> class VolumeButton : ToggleButton
29,30c26,29
< [DllImport ("libmuine")]
< private static extern IntPtr volume_button_new ();
---
> private Image icon;
> private Window popup;
> private int volume;
> private int revert_volume;
32,35c31,32
< [DllImport ("libgobject-2.0-0.dll")]
< private static extern uint g_signal_connect_data (IntPtr obj, string name,
< SignalDelegate cb, IntPtr data,
< IntPtr p, int flags);
---
> /* GDK_CURRENT_TIME doesn't seem to have an equiv in gtk-sharp yet. */
> const uint CURRENT_TIME = 0;
37,39c34,60
< public VolumeButton () : base (IntPtr.Zero)
< {
< Raw = volume_button_new ();
---
> public int Volume {
> set {
> string id = "muine-volume-";
>
> volume = value;
>
> if (volume <= 0)
> id += "zero";
> else if (volume <= 100 / 3)
> id += "min";
> else if (volume <= 200 / 3)
> id += "medium";
> else
> id += "max";
>
> icon.SetFromStock (id, IconSize.LargeToolbar);
>
> VolumeChanged (Volume);
> }
>
> get {
> return volume;
> }
> }
>
> public delegate void VolumeChangedHandler (int vol);
> public event VolumeChangedHandler VolumeChanged;
41,42c62,73
< g_signal_connect_data (Raw, "volume_changed", new SignalDelegate (VolumeChangedCallback),
< IntPtr.Zero, IntPtr.Zero, 0);
---
> public VolumeButton () : base ()
> {
> icon = new Image ();
> icon.Show ();
> Add (icon);
>
> popup = null;
>
> ScrollEvent += new ScrollEventHandler (ScrollHandler);
> Toggled += new EventHandler (ToggleHandler);
>
> Flags |= (int)WidgetFlags.NoWindow;
50,55c81,165
< [DllImport ("libmuine")]
< private static extern void volume_button_set_volume (IntPtr btn, int vol);
<
< public int Volume {
< set {
< volume_button_set_volume (Raw, value);
---
> private void ShowScale ()
> {
> VScale scale;
> VBox box;
> Adjustment adj;
> Frame frame;
> Label label;
> Image vol_icon_top;
> Image vol_icon_bottom;
> Requisition req;
> int x, y;
>
> /* Check point the volume so that we can restore it if the user rejects the slider changes. */
> revert_volume = Volume;
>
> popup = new Window (WindowType.Popup);
> popup.Screen = this.Screen;
>
> frame = new Frame ();
> frame.Shadow = ShadowType.Out;
> frame.Show ();
>
> popup.Add (frame);
>
> box = new VBox (false, 0);
> box.Show();
>
> frame.Add (box);
>
> adj = new Adjustment (volume, 0, 100, 5, 10, 0);
>
> scale = new VScale (adj);
> scale.ValueChanged += new EventHandler (ScaleValueChanged);
> scale.KeyPressEvent += new KeyPressEventHandler (ScaleKeyPressed);
> popup.ButtonPressEvent += new ButtonPressEventHandler (PopupButtonPressed);
>
> scale.Adjustment.Upper = 100.0;
> scale.Adjustment.Lower = 0.0;
> scale.DrawValue = false;
> scale.UpdatePolicy = UpdateType.Continuous;
> scale.Inverted = true;
>
> scale.Show ();
>
> label = new Label ("+");
> label.Show ();
> box.PackStart (label, false, true, 0);
>
> label = new Label ("-");
> label.Show ();
> box.PackEnd (label, false, true, 0);
>
> box.PackStart (scale, true, true, 0);
>
> req = SizeRequest ();
>
> GdkWindow.GetOrigin (out x, out y);
>
> scale.SetSizeRequest (-1, 100);
> popup.SetSizeRequest (req.Width, -1);
>
> popup.Move (x + Allocation.X, y + Allocation.Y + req.Height);
> popup.Show ();
>
> popup.GrabFocus ();
>
> Grab.Add (popup);
>
> Gdk.GrabStatus grabbed = Gdk.Pointer.Grab (popup.GdkWindow, true,
> Gdk.EventMask.ButtonPressMask | Gdk.EventMask.ButtonReleaseMask | Gdk.EventMask.PointerMotionMask,
> null, null,
> CURRENT_TIME);
>
> if (grabbed == Gdk.GrabStatus.Success) {
> grabbed = Gdk.Keyboard.Grab (popup.GdkWindow, true, CURRENT_TIME);
>
> if (grabbed != Gdk.GrabStatus.Success) {
> Grab.Remove (popup);
> popup.Destroy ();
> popup = null;
> }
> } else {
> Grab.Remove (popup);
> popup.Destroy ();
> popup = null;
59,60c169,178
< public delegate void VolumeChangedHandler (int vol);
< public event VolumeChangedHandler VolumeChanged;
---
> private void HideScale ()
> {
> if (popup != null) {
> Grab.Remove (popup);
> Gdk.Pointer.Ungrab (CURRENT_TIME);
> Gdk.Keyboard.Ungrab (CURRENT_TIME);
>
> popup.Destroy ();
> popup = null;
> }
62c180,181
< private delegate void SignalDelegate (IntPtr obj, int vol);
---
> Active = false;
> }
64c183
< private void VolumeChangedCallback (IntPtr obj, int vol)
---
> private void ToggleHandler (object obj, EventArgs args)
66,67c185,244
< if (VolumeChanged != null)
< VolumeChanged (vol);
---
> if (Active) {
> ShowScale ();
> }
> else {
> HideScale ();
> }
> }
>
> private void ScrollHandler (object obj, ScrollEventArgs args)
> {
> int tmp_vol = Volume;
>
> switch (args.Event.Direction) {
> case Gdk.ScrollDirection.Up:
> tmp_vol += 10;
> break;
> case Gdk.ScrollDirection.Down:
> tmp_vol -= 10;
> break;
> default:
> break;
> }
>
> // A CLAMP equiv doesn't seem to exist ... doing that manually
> tmp_vol = Math.Min (100, tmp_vol);
> tmp_vol = Math.Max (0, tmp_vol);
>
> Volume = tmp_vol;
> }
>
> private void ScaleValueChanged (object obj, EventArgs args)
> {
> Volume = (int)((VScale)obj).Value;
> }
>
> private void ScaleKeyPressed (object obj, KeyPressEventArgs args)
> {
> switch (args.Event.Key) {
> case Gdk.Key.Escape:
> HideScale ();
> Volume = revert_volume;
> break;
> case Gdk.Key.KP_Enter:
> case Gdk.Key.ISO_Enter:
> case Gdk.Key.Key_3270_Enter:
> case Gdk.Key.Return:
> case Gdk.Key.space:
> case Gdk.Key.KP_Space:
> HideScale ();
> break;
> default:
> break;
> }
> }
>
> private void PopupButtonPressed (object obj, ButtonPressEventArgs args)
> {
> if (popup != null) {
> HideScale ();
> }
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]