# HG changeset patch # User Ivo Smits # Date 1403801156 -7200 # Node ID ebdff34b9e4fc6d7fde216de61684ca0d8edf573 # Parent 9b898d8b2541558891838b2af2e3493854bd0480# Parent 3c1bba376dca53c28b079319147a1370d7f5daa8 Merge diff -r 9b898d8b2541 -r ebdff34b9e4f FBGUI/FBGUI.cs --- a/FBGUI/FBGUI.cs Thu Jun 05 00:46:15 2014 +0200 +++ b/FBGUI/FBGUI.cs Thu Jun 26 18:45:56 2014 +0200 @@ -8,6 +8,7 @@ using System.Reflection; using System.Threading; using System.Windows.Forms; +using UCIS.Util; using UCIS.VNCServer; using ThreadingTimer = System.Threading.Timer; @@ -93,7 +94,7 @@ } public interface IFBGContainerControl { void AddControl(IFBGControl control); - void RemoveControl(IFBGControl control); + Boolean RemoveControl(IFBGControl control); void HandleMessage(IFBGControl sender, FBGMessage e); Size ClientSize { get; } } @@ -212,8 +213,8 @@ protected void RaiseEvent(EventHandler eh, EventArgs ea) { if (eh != null) eh(this, ea); } protected void RaiseEvent(EventHandler eh) { if (eh != null) eh(this, new EventArgs()); } } - public class FBGContainerControl : FBGControl, IFBGContainerControl { - protected List controls = new List(); + public class FBGContainerControl : FBGControl, IFBGContainerControl, IList { + protected IFBGControl[] controls = new IFBGControl[0]; protected IFBGControl mouseCaptureControl = null; protected IFBGControl keyboardCaptureControl = null; public virtual Rectangle ClientRectangle { get { return new Rectangle(Point.Empty, Bounds.Size); } } @@ -221,18 +222,27 @@ public FBGContainerControl(IFBGContainerControl parent) : base(parent) { } void IFBGContainerControl.AddControl(IFBGControl control) { AddControl(control); } protected virtual void AddControl(IFBGControl control) { - controls.Add(control); + ArrayUtil.Add(ref controls, control); if (control.Visible) Invalidate(control); } - public virtual void RemoveControl(IFBGControl control) { - if (controls.Remove(control)) { - if (control.Visible) Invalidate(control); + public virtual Boolean RemoveControl(IFBGControl control) { + if (!ArrayUtil.Remove(ref controls, control)) return false; + if (control.Visible) Invalidate(control); + HandleMessage(control, new FBGPointingCaptureMessage(control, false)); + HandleMessage(control, new FBGKeyboardCaptureMessage(control, false)); + control.Orphaned(); + return true; + } + public virtual void RemoveAllControls() { + IFBGControl[] c = Interlocked.Exchange(ref controls, new IFBGControl[0]); + foreach (IFBGControl control in c) { HandleMessage(control, new FBGPointingCaptureMessage(control, false)); HandleMessage(control, new FBGKeyboardCaptureMessage(control, false)); control.Orphaned(); } + Invalidate(); } - public IList Controls { get { return controls.AsReadOnly(); } } + public IList Controls { get { return this; } } public virtual Point PointToChild(IFBGControl child, Point point) { return point - (Size)child.Bounds.Location - (Size)ClientRectangle.Location; } @@ -240,10 +250,11 @@ return point + (Size)child.Bounds.Location + (Size)ClientRectangle.Location; } public virtual void BringControlToFront(IFBGControl control) { - if (controls.Count == 0) return; - if (ReferenceEquals(controls[controls.Count - 1], control)) return; - if (!controls.Remove(control)) return; - controls.Add(control); + if (controls.Length == 0) return; + int oldindex = Array.IndexOf(controls, control); + if (oldindex == -1 || oldindex == controls.Length - 1) return; + for (int i = oldindex; i < controls.Length - 1; i++) controls[i] = controls[i + 1]; + controls[controls.Length - 1] = control; if (control.Visible) Invalidate(control); } public virtual void Invalidate(IFBGControl control) { @@ -278,7 +289,7 @@ Rectangle childarea = ClientRectangle; if (!childarea.Contains(p)) return null; p.Offset(-childarea.X, -childarea.Y); - return ((List)controls).FindLast(delegate(IFBGControl control) { return control.Visible && control.Bounds.Contains(p); }); + return Array.FindLast(controls, delegate(IFBGControl control) { return control.Visible && control.Bounds.Contains(p); }); } protected override void HandlePointingEvent(FBGPointingEvent e) { IFBGControl control = mouseCaptureControl != null ? mouseCaptureControl : FindControlAtPosition(e.Position); @@ -328,13 +339,31 @@ base.HandleKeyboardCaptureEvent(e); } protected override void Orphaned() { - base.Orphaned(); - IFBGControl[] c = controls.ToArray(); - controls.Clear(); + IFBGControl[] c = Interlocked.Exchange(ref controls, new IFBGControl[0]); foreach (IFBGControl control in c) control.Orphaned(); mouseCaptureControl = null; keyboardCaptureControl = null; + base.Orphaned(); } + + #region IList Members + int IList.IndexOf(IFBGControl item) { return Array.IndexOf(controls, item); } + void IList.Insert(int index, IFBGControl item) { throw new NotSupportedException(); } + void IList.RemoveAt(int index) { RemoveControl(controls[index]); } + IFBGControl IList.this[int index] { + get { return controls[index]; } + set { throw new NotSupportedException(); } + } + void ICollection.Add(IFBGControl item) { throw new NotSupportedException(); } + void ICollection.Clear() { RemoveAllControls(); } + bool ICollection.Contains(IFBGControl item) { return Array.IndexOf(controls, item) != -1; } + void ICollection.CopyTo(IFBGControl[] array, int arrayIndex) { controls.CopyTo(array, arrayIndex); } + int ICollection.Count { get { return controls.Length; } } + bool ICollection.IsReadOnly { get { return false; } } + bool ICollection.Remove(IFBGControl item) { return RemoveControl(item); } + IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)controls).GetEnumerator(); } + System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return controls.GetEnumerator(); } + #endregion } public class FBGDockContainer : FBGContainerControl { private Dictionary dockStyles = new Dictionary(); @@ -351,9 +380,14 @@ base.BringControlToFront(control); if (dockStyles.ContainsKey(control)) DoLayout(); } - public override void RemoveControl(IFBGControl control) { - base.RemoveControl(control); + public override Boolean RemoveControl(IFBGControl control) { + if (!base.RemoveControl(control)) return false; if (dockStyles.Remove(control)) DoLayout(); + return true; + } + public override void RemoveAllControls() { + base.RemoveAllControls(); + dockStyles.Clear(); } public override Rectangle Bounds { get { return base.Bounds; } @@ -384,7 +418,7 @@ public void SetDockStyle(IFBGControl control, DockStyle style) { if (style == DockStyle.None) { if (dockStyles.Remove(control)) DoLayout(); - } else if (controls.Contains(control)) { + } else if (Array.IndexOf(controls, control) != -1) { anchorStyles.Remove(control); dockStyles[control] = style; DoLayout(); @@ -398,13 +432,13 @@ public void SetAnchorStyle(IFBGControl control, AnchorStyles style) { if (style == (AnchorStyles.Left | AnchorStyles.Top)) { anchorStyles.Remove(control); - } else if (controls.Contains(control)) { + } else if (Array.IndexOf(controls, control) != -1) { dockStyles.Remove(control); anchorStyles[control] = style; } } public void SetAnchor(IFBGControl control, AnchorStyles style, int value) { - if (controls.Contains(control)) { + if (Array.IndexOf(controls, control) != -1) { AnchorStyles oldstyle; if (!anchorStyles.TryGetValue(control, out oldstyle)) oldstyle = AnchorStyles.Left | AnchorStyles.Top; Rectangle b = control.Bounds; @@ -496,13 +530,14 @@ control.Bounds = new Rectangle(Point.Empty, ClientSize); Invalidate(control.Bounds); } - void IFBGContainerControl.RemoveControl(IFBGControl control) { - if (!ReferenceEquals(childControl, control)) return; + Boolean IFBGContainerControl.RemoveControl(IFBGControl control) { + if (!ReferenceEquals(childControl, control)) return false; childControl = null; Invalidate(control.Bounds); if (mouseCaptureControl == control) mouseCaptureControl = null; if (keyboardCaptureControl == control) control = null; control.Orphaned(); + return true; } void IFBGContainerControl.HandleMessage(IFBGControl sender, FBGMessage e) { if (e is FBGInvalidateMessage) { @@ -623,6 +658,7 @@ public static readonly FBGCursor SizeBottomLeft = SizeTopLeft.RotateFlip(RotateFlipType.RotateNoneFlipY); public static readonly FBGCursor SizeBottomRight = SizeTopLeft.RotateFlip(RotateFlipType.RotateNoneFlipXY); public static readonly FBGCursor Hand = LoadFromResource("cursor_hand", 5, 0); + public static readonly FBGCursor IBeam = LoadFromResource("cursor_ibeam", 3, 7); public static FBGCursor ArrowCursor { get { return Arrow; } } } public class FBGRenderer : FBGContainerControl, IDisposable { @@ -1039,10 +1075,19 @@ } }; } - public override void RemoveControl(IFBGControl control) { - windowcontainer.RemoveControl(control); + public override Boolean RemoveControl(IFBGControl control) { + if (!windowcontainer.RemoveControl(control)) return false; + FBGWindowState ws = windowstates[control]; + menucontainer.RemoveControl(ws.MenuButton); windowstates.Remove(control); ScaleMenuButtons(); + return true; + } + public override void RemoveAllControls() { + windowcontainer.RemoveAllControls(); + menucontainer.RemoveAllControls(); + windowstates.Clear(); + ScaleMenuButtons(); } private void ScaleMenuButtons() { int bcount = windowstates.Count; @@ -1105,14 +1150,16 @@ public FBGTextBox(IFBGContainerControl parent) : base(parent) { BackColor = Color.White; Size = new Size(200, 20); + Cursor = FBGCursor.IBeam; } private String text = String.Empty; private Char passwordChar = (Char)0; private Font font = new Font(FontFamily.GenericMonospace, 10); private Brush brush = SystemBrushes.ControlText; private Boolean hasKeyboardFocus = false; - public String Text { get { return text; } set { text = value; if (CaretPosition > text.Length) CaretPosition = text.Length; Invalidate(); RaiseEvent(TextChanged); } } - public Font Font { get { return font; } set { font = value; Invalidate(); } } + private float[] characterPositions = null; + public String Text { get { return text; } set { text = value; if (CaretPosition > text.Length) CaretPosition = text.Length; characterPositions = null; Invalidate(); RaiseEvent(TextChanged); } } + public Font Font { get { return font; } set { font = value; characterPositions = null; Invalidate(); } } public Brush Brush { get { return brush; } set { brush = value; Invalidate(); } } public Color Color { set { Brush = new SolidBrush(value); } } public Int32 CaretPosition { get; private set; } @@ -1122,6 +1169,10 @@ protected override void Paint(Graphics g) { base.Paint(g); g.DrawRectangle(Pens.Gray, 0, 0, Bounds.Width - 1, Bounds.Height - 1); + float[] positions = characterPositions; + String textbuffer = text; + int textlength = textbuffer == null ? 0 : textbuffer.Length; + if (positions == null || positions.Length != textlength) characterPositions = positions = new float[text.Length]; using (StringFormat sf_nonprinting = new StringFormat(StringFormat.GenericTypographic)) { sf_nonprinting.Trimming = StringTrimming.None; sf_nonprinting.FormatFlags = StringFormatFlags.DisplayFormatControl | StringFormatFlags.MeasureTrailingSpaces; @@ -1129,43 +1180,28 @@ float x = 1; float y = 1; - float w = Width - 2; - if (hasKeyboardFocus && CaretPosition == 0) { - g.DrawLine(Pens.Black, x + 2, 2, x + 2, Height - 4); - } + if (hasKeyboardFocus && CaretPosition == 0) g.DrawLine(Pens.Black, x + 2, 2, x + 2, Height - 4); String c = passwordChar == 0 ? null : new String(passwordChar, 1); - for (int i = 0; i < text.Length; i++) { - if (passwordChar == 0) c = text.Substring(i, 1); - SizeF s = g.MeasureString(c, font, (int)Math.Ceiling(w), sf_nonprinting); + for (int i = 0; i < textlength; i++) { + if (passwordChar == 0) c = textbuffer.Substring(i, 1); g.DrawString(c, font, brush, x, y); + SizeF s = g.MeasureString(c, font, int.MaxValue, sf_nonprinting); x += (float)Math.Ceiling(s.Width); - w -= (float)Math.Ceiling(s.Width); + if (positions.Length > i) positions[i] = x; - if (hasKeyboardFocus && i == CaretPosition - 1) { - g.DrawLine(Pens.Black, x + 2, 2, x + 2, Height - 4); - } + if (hasKeyboardFocus && i == CaretPosition - 1) g.DrawLine(Pens.Black, x + 2, 2, x + 2, Height - 4); } } } + int GetCharacterIndexAtPosition(float x) { + float[] positions = characterPositions; + if (positions == null) return -1; + for (int i = 0; i < positions.Length; i++) if (x < characterPositions[i]) return i; + return characterPositions.Length; + } protected override void MouseDown(Point position, MouseButtons buttons) { hasKeyboardFocus = CaptureKeyboard(true); - CaretPosition = text.Length; - float x = 1; - String c = passwordChar == 0 ? null : new String(passwordChar, 1); - for (int i = 0; i < text.Length; i++) { - if (passwordChar == 0) c = text.Substring(i, 1); - Size s; - try { - s = TextRenderer.MeasureText(c, font, Size.Empty, TextFormatFlags.NoPadding | TextFormatFlags.NoPrefix); - } catch (Exception) { - break; - } - x += s.Width; - if (position.X < x) { - CaretPosition = i; - break; - } - } + CaretPosition = GetCharacterIndexAtPosition(position.X); Invalidate(); } protected override void KeyDown(Keys key) { @@ -1211,6 +1247,7 @@ } public void Focus() { hasKeyboardFocus = CaptureKeyboard(true); + Invalidate(); } protected override void LostKeyboardCapture() { base.LostKeyboardCapture(); @@ -1606,7 +1643,7 @@ base.Paint(g); g.DrawRectangle(Pens.DarkBlue, 0, 0, Bounds.Width - 1, Bounds.Height - 1); int lh = (int)Math.Ceiling(SystemFonts.DefaultFont.GetHeight()); - String text = SelectedText; + String text = Text; if (text == null) { g.FillRectangle(Brushes.DarkGray, 2, 2, Bounds.Width - 4 - 16, Bounds.Height - 4); } else { @@ -1621,7 +1658,7 @@ ControlPaint.DrawScrollButton(g, xoff, 1, 16, he, ScrollButton.Up, buttonUpState); ControlPaint.DrawScrollButton(g, xoff, Bounds.Height - he - 1, 16, he, ScrollButton.Down, buttonDownState); } - protected abstract String SelectedText { get; } + protected abstract String Text { get; } protected override void MouseDown(Point position, MouseButtons buttons) { CaptureKeyboard(true); if ((buttons & MouseButtons.Left) != 0) { @@ -1698,7 +1735,7 @@ } } } - protected override string SelectedText { + protected override string Text { get { if (selectedIndex == -1) return null; Object item = items[selectedIndex]; @@ -1741,7 +1778,7 @@ set { maximum = value; if (this.value > maximum) this.Value = maximum; } } public int Step { get; set; } - protected override string SelectedText { + protected override string Text { get { return value.ToString(); } } protected override void ButtonPressDown() { diff -r 9b898d8b2541 -r ebdff34b9e4f FBGUI/cursor_ibeam.png Binary file FBGUI/cursor_ibeam.png has changed diff -r 9b898d8b2541 -r ebdff34b9e4f Net/HTTP.cs --- a/Net/HTTP.cs Thu Jun 05 00:46:15 2014 +0200 +++ b/Net/HTTP.cs Thu Jun 26 18:45:56 2014 +0200 @@ -96,7 +96,7 @@ private PrebufferingStream Reader; private List RequestHeaders; private HTTPConnectionState State = HTTPConnectionState.Starting; - private KeyValuePair[] QueryParameters = null, PostParameters = null; + private KeyValuePair[] QueryParameters = null, PostParameters = null, Cookies = null; private HTTPOutputStream ResponseStream = null; private HTTPInputStream RequestStream = null; @@ -539,6 +539,7 @@ return list.ToArray(); } public KeyValuePair[] GetQueryParameters() { + if (RequestQuery == null) return new KeyValuePair[0]; if (QueryParameters == null) QueryParameters = DecodeUrlEncodedFields(RequestQuery); return QueryParameters; } @@ -565,6 +566,51 @@ return PostParameters; } + public String GetCookie(String name) { + foreach (KeyValuePair kvp in GetCookies()) if (kvp.Key == name) return kvp.Value; + return null; + } + public String[] GetCookies(String name) { + List list = new List(); + foreach (KeyValuePair kvp in GetCookies()) if (kvp.Key == name) list.Add(kvp.Value); + return list.ToArray(); + } + public KeyValuePair[] GetCookies() { + if (Cookies == null) { + String cookie = GetRequestHeader("Cookie"); + List> list = new List>(); + if (cookie != null) { + foreach (String part in cookie.Split(';', ',')) { + String[] subparts = part.Split('='); + String key = subparts[0].Trim(' ', '\t', '"'); + String value = (subparts.Length < 2) ? null : subparts[1].Trim(' ', '\t', '"'); + list.Add(new KeyValuePair(key, value)); + } + } + Cookies = list.ToArray(); + } + return Cookies; + } + + public void SetCookie(String name, String value) { + SendHeader("Set-Cookie", String.Format("{0}={1}", name, value)); + } + public void SetCookie(String name, String value, DateTime expire) { + SendHeader("Set-Cookie", String.Format("{0}={1}; Expires={2:R}", name, value, expire)); + } + public void SetCookie(String name, String value, DateTime? expire, String path, String domain, Boolean secure, Boolean httponly) { + StringBuilder sb = new StringBuilder(); + sb.Append(name); + sb.Append("="); + sb.Append(value); + if (expire != null) sb.AppendFormat("; Expires={0:R}", expire.Value.ToUniversalTime()); + if (path != null) sb.AppendFormat("; Path={0}", path); + if (domain != null) sb.AppendFormat("; Domain={0}", domain); + if (secure) sb.Append("; Secure"); + if (httponly) sb.Append("; HttpOnly"); + SendHeader("Set-Cookie", sb.ToString()); + } + public Stream OpenRequestStream() { if (RequestStream == null) RequestStream = new HTTPInputStream(this); return RequestStream; @@ -708,6 +754,9 @@ } public void AddPrefix(String prefix, IHTTPContentProvider contentProvider) { Prefixes.Add(new KeyValuePair(prefix, contentProvider)); + Prefixes.Sort(delegate(KeyValuePair a, KeyValuePair b) { + return -String.CompareOrdinal(a.Key, b.Key); + }); } public void DeletePrefix(String prefix) { Prefixes.RemoveAll(delegate(KeyValuePair item) { return prefix.Equals(item.Key, PrefixComparison); }); diff -r 9b898d8b2541 -r ebdff34b9e4f Pml/PmlConnection.cs --- a/Pml/PmlConnection.cs Thu Jun 05 00:46:15 2014 +0200 +++ b/Pml/PmlConnection.cs Thu Jun 26 18:45:56 2014 +0200 @@ -307,7 +307,7 @@ } } } catch (System.Threading.ThreadAbortException ex) { - throw ex; + throw; } catch (Exception ex) { Console.WriteLine(ex.ToString()); } finally { diff -r 9b898d8b2541 -r ebdff34b9e4f UCIS.Core.csproj --- a/UCIS.Core.csproj Thu Jun 05 00:46:15 2014 +0200 +++ b/UCIS.Core.csproj Thu Jun 26 18:45:56 2014 +0200 @@ -194,6 +194,9 @@ + + +