diff --git a/shadowsocks-csharp/Properties/Resources.Designer.cs b/shadowsocks-csharp/Properties/Resources.Designer.cs
index 5139429f..f6db05ad 100755
--- a/shadowsocks-csharp/Properties/Resources.Designer.cs
+++ b/shadowsocks-csharp/Properties/Resources.Designer.cs
@@ -76,12 +76,13 @@ namespace Shadowsocks.Properties {
///Mode=代理模式
///PAC=PAC 模式
///Global=全局模式
- ///Servers=服务器选择
+ ///Servers=服务器
///Edit Servers...=编辑服务器...
///Start on Boot=开机启动
///Share over LAN=在局域网共享代理
///Edit PAC File...=编辑 PAC 文件...
///Show QRCode...=显示二维码...
+ ///Scan QRCode from Screen...=扫描屏幕上的二维码...
///Show Logs...=显示日志...
///About...=关于...
///Quit=退出
@@ -99,9 +100,7 @@ namespace Shadowsocks.Properties {
///Cancel=取消
///New server=未配置的服务器
///QRCode=二维码
- ///Shadowsocks Error: {0}=Shadowsocks 错误: {0}
- ///Port already in use=端口已被占用
- ///Il [rest of string was truncated]";.
+ ///Shadowsocks Error: {0}=Shadowsocks [rest of string was truncated]";.
///
internal static string cn {
get {
diff --git a/shadowsocks-csharp/View/MenuViewController.cs b/shadowsocks-csharp/View/MenuViewController.cs
index f8b33e92..1794e7e2 100755
--- a/shadowsocks-csharp/View/MenuViewController.cs
+++ b/shadowsocks-csharp/View/MenuViewController.cs
@@ -425,10 +425,10 @@ namespace Shadowsocks.View
maxX += margin + marginLeft;
minY += -margin + marginTop;
maxY += margin + marginTop;
- splash.Location = new Point((int)minX, (int)minY);
+ splash.Location = new Point(0, 0);
// we need a panel because a window has a minimal size
- splash.Panel.Size = new Size((int)maxX - (int)minX, (int)maxY - (int)minY);
- splash.Size = splash.Panel.Size;
+ splash.TargetRect = new Rectangle((int)minX, (int)minY, (int)maxX - (int)minX, (int)maxY - (int)minY);
+ splash.Size = new Size(fullImage.Width, fullImage.Height);
splash.Show();
return;
}
diff --git a/shadowsocks-csharp/View/QRCodeSplashForm.Designer.cs b/shadowsocks-csharp/View/QRCodeSplashForm.Designer.cs
deleted file mode 100755
index 0c7e1601..00000000
--- a/shadowsocks-csharp/View/QRCodeSplashForm.Designer.cs
+++ /dev/null
@@ -1,72 +0,0 @@
-namespace Shadowsocks.View
-{
- partial class QRCodeSplashForm
- {
- ///
- /// Required designer variable.
- ///
- private System.ComponentModel.IContainer components = null;
-
- ///
- /// Clean up any resources being used.
- ///
- /// true if managed resources should be disposed; otherwise, false.
- protected override void Dispose(bool disposing)
- {
- if (disposing && (components != null))
- {
- components.Dispose();
- }
- base.Dispose(disposing);
- }
-
- #region Windows Form Designer generated code
-
- ///
- /// Required method for Designer support - do not modify
- /// the contents of this method with the code editor.
- ///
- private void InitializeComponent()
- {
- this.Panel = new System.Windows.Forms.Panel();
- this.SuspendLayout();
- //
- // Panel
- //
- this.Panel.BackColor = System.Drawing.Color.Crimson;
- this.Panel.Location = new System.Drawing.Point(0, 0);
- this.Panel.Margin = new System.Windows.Forms.Padding(0);
- this.Panel.Name = "Panel";
- this.Panel.Size = new System.Drawing.Size(168, 158);
- this.Panel.TabIndex = 0;
- //
- // QRCodeSplashForm
- //
- this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None;
- this.BackColor = System.Drawing.Color.White;
- this.ClientSize = new System.Drawing.Size(284, 262);
- this.ControlBox = false;
- this.Controls.Add(this.Panel);
- this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
- this.MaximizeBox = false;
- this.MinimizeBox = false;
- this.Name = "QRCodeSplashForm";
- this.Opacity = 0.3D;
- this.ShowIcon = false;
- this.ShowInTaskbar = false;
- this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide;
- this.StartPosition = System.Windows.Forms.FormStartPosition.Manual;
- this.Text = "QRCodeSplashForm";
- this.TopMost = true;
- this.TransparencyKey = System.Drawing.Color.White;
- this.Load += new System.EventHandler(this.QRCodeSplashForm_Load);
- this.ResumeLayout(false);
-
- }
-
- #endregion
-
- public System.Windows.Forms.Panel Panel;
-
- }
-}
\ No newline at end of file
diff --git a/shadowsocks-csharp/View/QRCodeSplashForm.cs b/shadowsocks-csharp/View/QRCodeSplashForm.cs
index 3d14785e..f18377b9 100755
--- a/shadowsocks-csharp/View/QRCodeSplashForm.cs
+++ b/shadowsocks-csharp/View/QRCodeSplashForm.cs
@@ -5,60 +5,321 @@ using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
+using System.Drawing.Imaging;
+using System.Runtime.InteropServices;
+
namespace Shadowsocks.View
{
- public partial class QRCodeSplashForm : Form
+ public class QRCodeSplashForm : PerPixelAlphaForm
{
+ public class QRRectView : Control
+ {
+ private Pen pen;
+ private Brush brush;
+
+ public QRRectView()
+ {
+ pen = new Pen(Color.Red, 3);
+ brush = new SolidBrush(Color.FromArgb(100, Color.Red));
+ SetStyle(ControlStyles.ResizeRedraw, true);
+ SetStyle(ControlStyles.SupportsTransparentBackColor, true);
+ this.BackColor = Color.Transparent;
+ this.DoubleBuffered = true;
+ }
+
+ protected override void OnPaint(PaintEventArgs e)
+ {
+ Graphics g = e.Graphics;
+ g.FillRectangle(brush, 0, 0, Width, Height);
+ g.DrawRectangle(pen, 0, 0, Width, Height);
+ }
+ }
+ public Rectangle TargetRect;
+
public QRCodeSplashForm()
{
- InitializeComponent();
+ this.Load += QRCodeSplashForm_Load;
+ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None;
+ this.BackColor = System.Drawing.Color.White;
+ this.ClientSize = new System.Drawing.Size(284, 262);
+ this.ControlBox = false;
+ this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
+ this.MaximizeBox = false;
+ this.MinimizeBox = false;
+ this.Name = "QRCodeSplashForm";
+ this.ShowIcon = false;
+ this.ShowInTaskbar = false;
+ this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide;
+ this.StartPosition = System.Windows.Forms.FormStartPosition.Manual;
+ this.TopMost = true;
+
}
private Timer timer;
- private int step;
+ private int animationStep;
+ private int flashStep;
+ private static int ANIMATION_STEPS = 30;
+ private static double ANIMATION_TIME = 0.3;
+ private QRRectView codeRectView;
+ int x;
+ int y;
+ int w;
+ int h;
+ Bitmap bitmap;
+ Graphics g;
+ Pen pen;
+ SolidBrush brush;
private void QRCodeSplashForm_Load(object sender, EventArgs e)
{
- step = 0;
+ SetStyle(ControlStyles.SupportsTransparentBackColor, true);
+ this.BackColor = Color.Transparent;
+ animationStep = 0;
+ flashStep = 0;
+ //codeRectView = new QRRectView();
+ x = 0;
+ y = 0;
+ w = Width;
+ h = Height;
+ //this.Controls.Add(codeRectView);
timer = new Timer();
- timer.Interval = 300;
+ timer.Interval = (int)(ANIMATION_TIME * 1000 / ANIMATION_STEPS);
timer.Tick += timer_Tick;
timer.Start();
+ bitmap = new Bitmap(Width, Height, PixelFormat.Format32bppArgb);
+ g = Graphics.FromImage(bitmap);
+ pen = new Pen(Color.Red, 3);
+ brush = new SolidBrush(Color.FromArgb(30, Color.Red));
}
- void timer_Tick(object sender, EventArgs e)
+ protected override CreateParams CreateParams
{
- timer.Interval = 40;
- if (step == 0)
+ get
{
- this.Opacity = 0;
+ CreateParams cp = base.CreateParams;
+ cp.ExStyle |= 0x00080000; // This form has to have the WS_EX_LAYERED extended style
+ return cp;
}
- else if (step == 1)
- {
- this.Opacity = 0.3;
- }
- else if (step == 1)
+ }
+
+ void timer_Tick(object sender, EventArgs e)
+ {
+ if (animationStep < ANIMATION_STEPS)
{
- this.Opacity = 0.0;
+ animationStep++;
+ double percent = (double)animationStep / (double)ANIMATION_STEPS;
+ // ease out
+ percent = 1 - Math.Pow((1 - percent), 4);
+ x = (int)(TargetRect.X * percent);
+ y = (int)(TargetRect.Y * percent);
+ w = (int)(TargetRect.Width * percent + this.Size.Width * (1 - percent));
+ h = (int)(TargetRect.Height * percent + this.Size.Height * (1 - percent));
+ //codeRectView.Location = new Point(x, y);
+ //codeRectView.Size = new Size(w, h);
+ pen.Color = Color.FromArgb((int)(255 * percent), Color.Red);
+ brush.Color = Color.FromArgb((int)(30 * percent), Color.Red);
+ g.Clear(Color.Transparent);
+ g.FillRectangle(brush, x, y, w, h);
+ g.DrawRectangle(pen, x, y, w, h);
+ SetBitmap(bitmap);
}
- else if (step == 2)
+ else
{
- this.Opacity = 0.3;
+ timer.Interval = 50;
+ if (flashStep == 0)
+ {
+ g.Clear(Color.Transparent);
+ SetBitmap(bitmap);
+ }
+ else if (flashStep == 1)
+ {
+ g.FillRectangle(brush, x, y, w, h);
+ g.DrawRectangle(pen, x, y, w, h);
+ SetBitmap(bitmap);
+ }
+ else if (flashStep == 1)
+ {
+ g.Clear(Color.Transparent);
+ SetBitmap(bitmap);
+ }
+ else if (flashStep == 2)
+ {
+ g.FillRectangle(brush, x, y, w, h);
+ g.DrawRectangle(pen, x, y, w, h);
+ SetBitmap(bitmap);
+ }
+ else if (flashStep == 3)
+ {
+ g.Clear(Color.Transparent);
+ SetBitmap(bitmap);
+ }
+ else if (flashStep == 4)
+ {
+ g.FillRectangle(brush, x, y, w, h);
+ g.DrawRectangle(pen, x, y, w, h);
+ SetBitmap(bitmap);
+ }
+ else
+ {
+ timer.Stop();
+ pen.Dispose();
+ brush.Dispose();
+ bitmap.Dispose();
+ this.Close();
+ }
+ flashStep++;
}
- else if (step == 3)
+ }
+ }
+
+
+ // class that exposes needed win32 gdi functions.
+ class Win32
+ {
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct Point
+ {
+ public Int32 x;
+ public Int32 y;
+
+ public Point(Int32 x, Int32 y) { this.x = x; this.y = y; }
+ }
+
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct Size
+ {
+ public Int32 cx;
+ public Int32 cy;
+
+ public Size(Int32 cx, Int32 cy) { this.cx = cx; this.cy = cy; }
+ }
+
+
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ struct ARGB
+ {
+ public byte Blue;
+ public byte Green;
+ public byte Red;
+ public byte Alpha;
+ }
+
+
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ public struct BLENDFUNCTION
+ {
+ public byte BlendOp;
+ public byte BlendFlags;
+ public byte SourceConstantAlpha;
+ public byte AlphaFormat;
+ }
+
+
+ public const Int32 ULW_COLORKEY = 0x00000001;
+ public const Int32 ULW_ALPHA = 0x00000002;
+ public const Int32 ULW_OPAQUE = 0x00000004;
+
+ public const byte AC_SRC_OVER = 0x00;
+ public const byte AC_SRC_ALPHA = 0x01;
+
+
+ [DllImport("user32.dll", ExactSpelling = true, SetLastError = true)]
+ public static extern int UpdateLayeredWindow(IntPtr hwnd, IntPtr hdcDst, ref Point pptDst, ref Size psize, IntPtr hdcSrc, ref Point pprSrc, Int32 crKey, ref BLENDFUNCTION pblend, Int32 dwFlags);
+
+ [DllImport("user32.dll", ExactSpelling = true, SetLastError = true)]
+ public static extern IntPtr GetDC(IntPtr hWnd);
+
+ [DllImport("user32.dll", ExactSpelling = true)]
+ public static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC);
+
+ [DllImport("gdi32.dll", ExactSpelling = true, SetLastError = true)]
+ public static extern IntPtr CreateCompatibleDC(IntPtr hDC);
+
+ [DllImport("gdi32.dll", ExactSpelling = true, SetLastError = true)]
+ public static extern int DeleteDC(IntPtr hdc);
+
+ [DllImport("gdi32.dll", ExactSpelling = true)]
+ public static extern IntPtr SelectObject(IntPtr hDC, IntPtr hObject);
+
+ [DllImport("gdi32.dll", ExactSpelling = true, SetLastError = true)]
+ public static extern int DeleteObject(IntPtr hObject);
+ }
+
+
+ public class PerPixelAlphaForm : Form
+ {
+ // http://www.codeproject.com/Articles/1822/Per-Pixel-Alpha-Blend-in-C
+ // Rui Lopes
+
+ public PerPixelAlphaForm()
+ {
+ // This form should not have a border or else Windows will clip it.
+ FormBorderStyle = FormBorderStyle.None;
+ }
+
+ public void SetBitmap(Bitmap bitmap)
+ {
+ SetBitmap(bitmap, 255);
+ }
+
+
+ /// Changes the current bitmap with a custom opacity level. Here is where all happens!
+ public void SetBitmap(Bitmap bitmap, byte opacity)
+ {
+ if (bitmap.PixelFormat != PixelFormat.Format32bppArgb)
+ throw new ApplicationException("The bitmap must be 32ppp with alpha-channel.");
+
+ // The ideia of this is very simple,
+ // 1. Create a compatible DC with screen;
+ // 2. Select the bitmap with 32bpp with alpha-channel in the compatible DC;
+ // 3. Call the UpdateLayeredWindow.
+
+ IntPtr screenDc = Win32.GetDC(IntPtr.Zero);
+ IntPtr memDc = Win32.CreateCompatibleDC(screenDc);
+ IntPtr hBitmap = IntPtr.Zero;
+ IntPtr oldBitmap = IntPtr.Zero;
+
+ try
{
- this.Opacity = 0.0;
+ hBitmap = bitmap.GetHbitmap(Color.FromArgb(0)); // grab a GDI handle from this GDI+ bitmap
+ oldBitmap = Win32.SelectObject(memDc, hBitmap);
+
+ Win32.Size size = new Win32.Size(bitmap.Width, bitmap.Height);
+ Win32.Point pointSource = new Win32.Point(0, 0);
+ Win32.Point topPos = new Win32.Point(Left, Top);
+ Win32.BLENDFUNCTION blend = new Win32.BLENDFUNCTION();
+ blend.BlendOp = Win32.AC_SRC_OVER;
+ blend.BlendFlags = 0;
+ blend.SourceConstantAlpha = opacity;
+ blend.AlphaFormat = Win32.AC_SRC_ALPHA;
+
+ Win32.UpdateLayeredWindow(Handle, screenDc, ref topPos, ref size, memDc, ref pointSource, 0, ref blend, Win32.ULW_ALPHA);
}
- else if (step == 4)
+ finally
{
- this.Opacity = 0.3;
+ Win32.ReleaseDC(IntPtr.Zero, screenDc);
+ if (hBitmap != IntPtr.Zero)
+ {
+ Win32.SelectObject(memDc, oldBitmap);
+ //Windows.DeleteObject(hBitmap); // The documentation says that we have to use the Windows.DeleteObject... but since there is no such method I use the normal DeleteObject from Win32 GDI and it's working fine without any resource leak.
+ Win32.DeleteObject(hBitmap);
+ }
+ Win32.DeleteDC(memDc);
}
- else
+ }
+
+
+ protected override CreateParams CreateParams
+ {
+ get
{
- this.Close();
+ CreateParams cp = base.CreateParams;
+ cp.ExStyle |= 0x00080000; // This form has to have the WS_EX_LAYERED extended style
+ return cp;
}
- step++;
}
}
}
diff --git a/shadowsocks-csharp/View/QRCodeSplashForm.resx b/shadowsocks-csharp/View/QRCodeSplashForm.resx
deleted file mode 100755
index 5ea0895e..00000000
--- a/shadowsocks-csharp/View/QRCodeSplashForm.resx
+++ /dev/null
@@ -1,120 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- text/microsoft-resx
-
-
- 2.0
-
-
- System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
-
-
- System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
-
-
\ No newline at end of file
diff --git a/shadowsocks-csharp/shadowsocks-csharp.csproj b/shadowsocks-csharp/shadowsocks-csharp.csproj
index e5da1098..61820eaa 100755
--- a/shadowsocks-csharp/shadowsocks-csharp.csproj
+++ b/shadowsocks-csharp/shadowsocks-csharp.csproj
@@ -169,9 +169,6 @@
Form
-
- QRCodeSplashForm.cs
-
ConfigForm.cs
Designer
@@ -184,9 +181,6 @@
QRCodeForm.cs
-
- QRCodeSplashForm.cs
-
Designer