diff options
author | Vsevolod Kukol <sevoku@microsoft.com> | 2017-03-27 19:40:09 +0300 |
---|---|---|
committer | Vsevolod Kukol <sevoku@microsoft.com> | 2017-03-27 19:40:09 +0300 |
commit | bcf0f49ff6994d1dc2d06d53a7518ae1ed35c571 (patch) | |
tree | 160c92b456601f6a46d3660eb2bdbb2c4290f93c /main/src/core/MonoDevelop.Ide/MonoDevelop.Components | |
parent | 0be22f7c0a199f9ffb185386eb85b620d0f37f58 (diff) | |
parent | 252dc8bac40ca46bf020351e331aa477763a020d (diff) |
Merge remote-tracking branch 'origin/master' into native-popups
Diffstat (limited to 'main/src/core/MonoDevelop.Ide/MonoDevelop.Components')
13 files changed, 321 insertions, 19 deletions
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/CellRendererImage.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/CellRendererImage.cs index cf03ee4150..ec66e79929 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/CellRendererImage.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/CellRendererImage.cs @@ -27,6 +27,7 @@ using System; using Xwt.Drawing; using MonoDevelop.Core; using MonoDevelop.Ide; +using System.Runtime.InteropServices; namespace MonoDevelop.Components { diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/ContextMenuTreeView.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/ContextMenuTreeView.cs index 3d6e083a0f..87b795386a 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/ContextMenuTreeView.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/ContextMenuTreeView.cs @@ -24,6 +24,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. using System; +using MonoDevelop.Components.AtkCocoaHelper; namespace MonoDevelop.Components { @@ -32,8 +33,11 @@ namespace MonoDevelop.Components /// </summary> public class ContextMenuTreeView : Gtk.TreeView { + internal ActionDelegate ActionHandler { get; private set; } public ContextMenuTreeView () { + ActionHandler = new ActionDelegate (this); + ActionHandler.PerformShowMenu += PerformShowMenu; } public ContextMenuTreeView (Gtk.TreeModel model) : base (model) @@ -175,6 +179,11 @@ namespace MonoDevelop.Components return res; } + void PerformShowMenu (object sender, EventArgs args) + { + OnPopupMenu (); + } + protected override bool OnPopupMenu () { if (DoPopupMenu != null) { diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/DropDownBoxListWindow.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/DropDownBoxListWindow.cs index d65aa395f1..eb1620c397 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/DropDownBoxListWindow.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/DropDownBoxListWindow.cs @@ -28,6 +28,7 @@ using System; using MonoDevelop.Ide; using Gtk; using System.Text; +using MonoDevelop.Components.AtkCocoaHelper; using MonoDevelop.Ide.Fonts; namespace MonoDevelop.Components @@ -77,12 +78,16 @@ namespace MonoDevelop.Components public DropDownBoxListWindow (IListDataProvider provider, WindowType windowType) : base (windowType) { + Accessible.Name = "DropDownBoxListWindow"; + this.DataProvider = provider; this.TransientFor = IdeApp.Workbench.RootWindow; this.TypeHint = Gdk.WindowTypeHint.DropdownMenu; this.Decorated = false; this.BorderWidth = 1; list = new ListWidget (this); + list.Accessible.Name = "DropDownBoxListWindow.List"; + list.SelectItem += delegate { var sel = list.Selection; if (sel >= 0 && sel < DataProvider.IconCount) { @@ -235,12 +240,57 @@ namespace MonoDevelop.Components public ListWidget (DropDownBoxListWindow win) { + Accessible.Role = Atk.Role.List; this.win = win; this.Events = Gdk.EventMask.ButtonPressMask | Gdk.EventMask.ButtonReleaseMask | Gdk.EventMask.PointerMotionMask | Gdk.EventMask.LeaveNotifyMask; this.CanFocus = true; layout = new Pango.Layout (this.PangoContext); CalcRowHeight (); CalcVisibleRows (); + + CalcAccessibility (); + } + + class TextElement : AtkCocoaHelper.AccessibilityElementProxy + { + public int RowIndex { get; set; } + internal TextElement () + { + } + } + + void CalcAccessibility () + { + var columnElement = new AtkCocoaHelper.AccessibilityElementProxy (); + columnElement.GtkParent = this; + columnElement.SetRole (AtkCocoa.Roles.AXColumn); + Accessible.AddAccessibleElement (columnElement); + + for (int i = 0; i < win.DataProvider.IconCount; i++) { + var rowElement = new AtkCocoaHelper.AccessibilityElementProxy (); + rowElement.GtkParent = this; + rowElement.SetRole (AtkCocoa.Roles.AXRow); + Accessible.AddAccessibleElement (rowElement); + + var cellElement = new AtkCocoaHelper.AccessibilityElementProxy (); + cellElement.GtkParent = this; + cellElement.SetRole (AtkCocoa.Roles.AXCell); + columnElement.AddAccessibleChild (cellElement); + rowElement.AddAccessibleChild (cellElement); + + var textElement = new TextElement (); + textElement.RowIndex = i; + textElement.PerformPress += PerformPress; + textElement.GtkParent = this; + textElement.Value = win.DataProvider.GetMarkup (i); + cellElement.AddAccessibleChild (textElement); + } + } + + void PerformPress (object sender, EventArgs args) + { + var element = sender as TextElement; + win.DataProvider.ActivateItem (element.RowIndex); } internal void CalcRowHeight () diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/EventBoxTooltip.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/EventBoxTooltip.cs index 4e4de0a7dc..2ee1f64715 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/EventBoxTooltip.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/EventBoxTooltip.cs @@ -27,6 +27,7 @@ using Gtk;
using System;
+using MonoDevelop.Components.AtkCocoaHelper;
using MonoDevelop.Ide.Tasks;
namespace MonoDevelop.Components
@@ -38,6 +39,12 @@ namespace MonoDevelop.Components TooltipPopoverWindow tooltipWindow;
bool mouseOver;
+ public Atk.Object Accessible {
+ get {
+ return eventBox.Accessible;
+ }
+ }
+
/// <summary>
/// The EventBox should have Visible set to false otherwise the tooltip pop window
/// will have the wrong location.
@@ -49,7 +56,10 @@ namespace MonoDevelop.Components eventBox.EnterNotifyEvent += HandleEnterNotifyEvent;
eventBox.LeaveNotifyEvent += HandleLeaveNotifyEvent;
- Position = PopupPosition.TopLeft;
+ Position = PopupPosition.TopLeft; + + // Accessibility: Disguise this eventbox as a label
+ eventBox.Accessible.SetRole (AtkCocoa.Roles.AXStaticText);
}
[GLib.ConnectBefore]
@@ -66,6 +76,11 @@ namespace MonoDevelop.Components ShowTooltip ();
}
+ void UpdateAccessibility ()
+ {
+ eventBox.Accessible.SetLabel (tip);
+ }
+
bool ShowTooltip ()
{
if (!string.IsNullOrEmpty (tip)) {
@@ -106,6 +121,7 @@ namespace MonoDevelop.Components HideTooltip ();
} else if (!string.IsNullOrEmpty (tip) && mouseOver)
ShowTooltip ();
+ UpdateAccessibility ();
}
}
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/FileFilterSet.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/FileFilterSet.cs index 56cdc9262d..ef07a4f875 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/FileFilterSet.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/FileFilterSet.cs @@ -105,10 +105,15 @@ namespace MonoDevelop.Components { if (filterStrings == null) yield break; + var filterNames = new HashSet<string>(); foreach (string filterStr in filterStrings) { - var parts = filterStr.Split ('|'); - var f = new SelectFileDialogFilter (parts[0], parts[1].Split (';')); - yield return f; + var parts = filterStr.Split('|'); + var filterName = parts[0]; + if (filterNames.Add(filterName))
+ { + var f = new SelectFileDialogFilter(filterName, parts[1].Split(';'));
+ yield return f;
+ } } } diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/GtkWorkarounds.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/GtkWorkarounds.cs index ac0cb644d7..7ea0b8019b 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/GtkWorkarounds.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/GtkWorkarounds.cs @@ -1173,9 +1173,22 @@ namespace MonoDevelop.Components [DllImport (PangoUtil.LIBGOBJECT, CallingConvention = CallingConvention.Cdecl)] static extern IntPtr g_object_get_data (IntPtr source, string name); + [DllImport (PangoUtil.LIBGOBJECT, CallingConvention = CallingConvention.Cdecl)] + static extern void g_object_set_data (IntPtr source, string name, IntPtr dataHandle); + [DllImport (PangoUtil.LIBGTK, CallingConvention = CallingConvention.Cdecl)] static extern IntPtr gtk_icon_set_render_icon_scaled (IntPtr handle, IntPtr style, int direction, int state, int size, IntPtr widget, IntPtr intPtr, ref double scale); + public static IntPtr GetData (GLib.Object o, string name) + { + return g_object_get_data (o.Handle, name); + } + + public static void SetData (GLib.Object o, string name, IntPtr dataHandle) + { + g_object_set_data (o.Handle, name, dataHandle); + } + public static bool SetSourceScale (Gtk.IconSource source, double scale) { if (!supportsHiResIcons) diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/HoverImageButton.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/HoverImageButton.cs index 428c407851..e94f1d6c1a 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/HoverImageButton.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/HoverImageButton.cs @@ -29,6 +29,7 @@ using System; using Gtk; using MonoDevelop.Ide; +using MonoDevelop.Components.AtkCocoaHelper; namespace MonoDevelop.Components { @@ -55,11 +56,18 @@ namespace MonoDevelop.Components public HoverImageButton() { + var actionHandler = new ActionDelegate (this); + actionHandler.PerformPress += OnPerformPress; + + Accessible.SetRole (AtkCocoa.Roles.AXButton); + Gtk.Alignment al = new Alignment (0.5f, 0.5f, 0f, 0f); + al.Accessible.SetShouldIgnore (true); al.Show (); CanFocus = true; VisibleWindow = false; image = new ImageView(); + image.Accessible.SetShouldIgnore (true); image.Show(); al.Add (image); Add(al); @@ -83,6 +91,11 @@ namespace MonoDevelop.Components } } + void OnPerformPress (object sender, EventArgs args) + { + Activate (); + } + private bool changing_style = false; protected override void OnStyleSet(Style previous_style) { diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/IdeTheme.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/IdeTheme.cs index bfec7505bf..3f685d732b 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/IdeTheme.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/IdeTheme.cs @@ -67,11 +67,21 @@ namespace MonoDevelop.Components if (!Platform.IsLinux) UpdateGtkTheme (); + if (Platform.IsMac) { + // Load a private version of AtkCocoa stored in the XS app directory + var appDir = Directory.GetParent (AppDomain.CurrentDomain.BaseDirectory); + var gtkPath = $"{appDir.Parent.FullName}/lib/gtk-2.0"; + + LoggingService.LogInfo ($"Loading modules from {gtkPath}"); + Environment.SetEnvironmentVariable ("GTK_MODULES", $"{gtkPath}/libatkcocoa.so"); + } + Gtk.Application.Init (BrandingService.ApplicationName, ref args); // Reset our environment after initialization on Mac - if (Platform.IsMac) + if (Platform.IsMac) { Environment.SetEnvironmentVariable ("GTK2_RC_FILES", DefaultGtk2RcFiles); + } } internal static void SetupXwtTheme () diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/ImageButton.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/ImageButton.cs index c9e2d7d0fa..909723e192 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/ImageButton.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/ImageButton.cs @@ -24,6 +24,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. using System; +using MonoDevelop.Components.AtkCocoaHelper; using MonoDevelop.Ide; namespace MonoDevelop.Components @@ -39,9 +40,15 @@ namespace MonoDevelop.Components public ImageButton () { + var actionHandler = new ActionDelegate (this); + actionHandler.PerformPress += HandlePress; + + Accessible.Role = Atk.Role.PushButton; + Events |= Gdk.EventMask.EnterNotifyMask | Gdk.EventMask.LeaveNotifyMask | Gdk.EventMask.ButtonReleaseMask; VisibleWindow = false; imageWidget = new ImageView (); + imageWidget.Accessible.SetShouldIgnore (true); imageWidget.Show (); Add (imageWidget); } @@ -123,6 +130,11 @@ namespace MonoDevelop.Components return base.OnButtonReleaseEvent (evnt); } + void HandlePress (object o, EventArgs args) + { + Clicked?.Invoke (this, EventArgs.Empty); + } + public event EventHandler Clicked; } } diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/ImageView.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/ImageView.cs index 6760f647d5..e228d77788 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/ImageView.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/ImageView.cs @@ -37,6 +37,7 @@ namespace MonoDevelop.Components public ImageView () { + Accessible.Role = Atk.Role.Image; WidgetFlags |= Gtk.WidgetFlags.AppPaintable | Gtk.WidgetFlags.NoWindow; } diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/PathBar.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/PathBar.cs index defe968695..e4ddd5f43c 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/PathBar.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/PathBar.cs @@ -33,6 +33,8 @@ using MonoDevelop.Ide; using MonoDevelop.Ide.Gui; using MonoDevelop.Core.Text; using MonoDevelop.Ide.Fonts; +using MonoDevelop.Core; +using MonoDevelop.Components.AtkCocoaHelper; namespace MonoDevelop.Components { @@ -70,16 +72,31 @@ namespace MonoDevelop.Components get; set; } - - public PathEntry (Xwt.Drawing.Image icon, string markup) + + internal AtkCocoaHelper.AccessibilityElementProxy Accessible { + get; + set; + } + + PathEntry () + { + //Accessible = new AtkCocoaHelper.AccessibilityElementButtonProxy (); + Accessible = AccessibilityElementProxy.ButtonElementProxy (); + Accessible.Identifier = "Breadcrumb"; + Accessible.PerformPress += OnPerformShowMenu; + } + + public PathEntry (Xwt.Drawing.Image icon, string markup) : this (markup) { this.Icon = icon; - this.Markup = markup; } - public PathEntry (string markup) + public PathEntry (string markup) : this () { this.Markup = markup; + + // FIXME: Remove markup from this string? + Accessible.Label = markup; } public override bool Equals (object obj) @@ -113,6 +130,12 @@ namespace MonoDevelop.Components return darkIcon; } } + + internal event EventHandler PerformShowMenu; + void OnPerformShowMenu (object sender, EventArgs e) + { + PerformShowMenu?.Invoke (this, EventArgs.Empty); + } } class PathBar : Gtk.DrawingArea @@ -158,6 +181,10 @@ namespace MonoDevelop.Components public PathBar (Func<int, Control> createMenuForItem) { + Accessible.Name = "PathBar"; + Accessible.SetLabel (GettextCatalog.GetString ("Breadcrumb Bar")); + Accessible.Description = GettextCatalog.GetString ("Jump to definitions in the current file"); + this.Events = EventMask.ExposureMask | EventMask.EnterNotifyMask | EventMask.LeaveNotifyMask | @@ -180,7 +207,28 @@ namespace MonoDevelop.Components public new PathEntry[] Path { get; private set; } public int ActiveIndex { get { return activeIndex; } } - + + void UpdatePathAccessibility () + { + var elements = new AtkCocoaHelper.AccessibilityElementProxy [leftPath.Length + rightPath.Length]; + int idx = 0; + + foreach (var entry in leftPath) { + elements [idx] = entry.Accessible; + entry.Accessible.GtkParent = this; + entry.PerformShowMenu += PerformShowMenu; + idx++; + } + foreach (var entry in rightPath) { + elements [idx] = entry.Accessible; + entry.Accessible.GtkParent = this; + entry.PerformShowMenu += PerformShowMenu; + idx++; + } + + Accessible.ReplaceAccessibilityElements (elements); + } + public void SetPath (PathEntry[] path) { if (ArrSame (this.leftPath, path)) @@ -196,6 +244,8 @@ namespace MonoDevelop.Components widths = null; EnsureWidths (); QueueResize (); + + UpdatePathAccessibility (); } bool ArrSame (PathEntry[] a, PathEntry[] b) @@ -243,7 +293,16 @@ namespace MonoDevelop.Components } return currentWidths; } - + + void SetAccessibilityFrame (PathEntry entry, int x, int width) + { + int y = topPadding - buttonPadding; + int height = Allocation.Height - topPadding - bottomPadding + buttonPadding * 2; + Gdk.Rectangle rect = new Gdk.Rectangle (x, y, width, height); + + entry.Accessible.FrameInGtkParent = rect; + } + protected override bool OnExposeEvent (EventExpose evnt) { using (var ctx = Gdk.CairoHelper.Create (GdkWindow)) { @@ -272,6 +331,8 @@ namespace MonoDevelop.Components int x = xpos; xpos += itemWidth; + SetAccessibilityFrame (leftPath [i], x, itemWidth); + if (hoverIndex >= 0 && hoverIndex < Path.Length && leftPath [i] == Path [hoverIndex] && (menuVisible || pressed || hovering)) DrawButtonBorder (ctx, x - padding, itemWidth + padding + padding); @@ -331,7 +392,9 @@ namespace MonoDevelop.Components xposRight -= arrowSize; int x = xposRight; - + + SetAccessibilityFrame (rightPath [i], x, itemWidth); + if (hoverIndex >= 0 && hoverIndex < Path.Length && rightPath [i] == Path [hoverIndex] && (menuVisible || pressed || hovering)) DrawButtonBorder (ctx, x - padding, itemWidth + padding + padding); @@ -440,7 +503,30 @@ namespace MonoDevelop.Components } return true; } - + + void PerformShowMenu (object sender, EventArgs e) + { + int idx = 0; + + foreach (var entry in Path) { + if (entry == sender) { + hoverIndex = idx; + pressHoverIndex = idx; + break; + } + + idx++; + } + + Console.WriteLine ($"path item: {idx}"); + if (idx == Path.Length) { + return; + } + + Console.WriteLine ("Showing menu"); + ShowMenu (); + } + protected override bool OnButtonReleaseEvent (EventButton evnt) { pressed = false; diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/SearchEntry.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/SearchEntry.cs index b263f4315c..b37da712b6 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/SearchEntry.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/SearchEntry.cs @@ -32,6 +32,7 @@ using Gtk; using MonoDevelop.Core; using MonoDevelop.Ide.Fonts; using MonoDevelop.Ide.Gui; +using MonoDevelop.Components.AtkCocoaHelper; namespace MonoDevelop.Components { @@ -151,17 +152,30 @@ namespace MonoDevelop.Components private void BuildWidget () { alignment = new Alignment (0.5f, 0.5f, 1f, 0f); + alignment.Accessible.SetShouldIgnore (true); alignment.SetPadding (1, 1, 3, 3); VisibleWindow = false; box = new HBox (); + box.Accessible.SetShouldIgnore (true); entry = new FramelessEntry (this); entry.UseNativeContextMenus (); + entry.Accessible.SetSubRole ("AXSearchField"); filter_button = new HoverImageButton (IconSize.Menu, "md-searchbox-search"); + filter_button.Accessible.SetRole (AtkCocoa.Roles.AXMenuButton); + filter_button.Accessible.SetLabel (GettextCatalog.GetString ("Search filter menu")); + filter_button.Accessible.Description = GettextCatalog.GetString ("Change the search filters"); + + // This will be set to false if an event handler is attached to RequestMenu + filter_button.Accessible.SetShouldIgnore (true); + clear_button = new HoverImageButton (IconSize.Menu, "md-searchbox-clear"); + clear_button.Accessible.SetLabel (GettextCatalog.GetString ("Clear")); + clear_button.Accessible.Description = GettextCatalog.GetString ("Clear the search entry"); entryAlignment = new Gtk.Alignment (0.5f, 0.5f, 1f, 1f); + entryAlignment.Accessible.SetShouldIgnore (true); alignment.SetPadding (0, 0, 3, 3); entryAlignment.Add (entry); box.PackStart (filter_button, false, false, 0); @@ -356,12 +370,28 @@ namespace MonoDevelop.Components protected virtual void OnRequestMenu (EventArgs e) { - EventHandler handler = this.RequestMenu; - if (handler != null) - handler (this, e); + requestMenu?.Invoke (this, e); } - public event EventHandler RequestMenu; + event EventHandler requestMenu; + object requestMenuLock = new object (); + public event EventHandler RequestMenu { + add { + lock (requestMenuLock) { + requestMenu += value; + filter_button.Accessible.SetShouldIgnore (false); + } + } + + remove { + lock (requestMenuLock) { + requestMenu -= value; + if (requestMenu == null) { + filter_button.Accessible.SetShouldIgnore (true); + } + } + } + } public void GrabFocusEntry () { diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/Tabstrip.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/Tabstrip.cs index ac16bee985..ca25c7f6da 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/Tabstrip.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components/Tabstrip.cs @@ -31,6 +31,7 @@ using System.Drawing.Design; using Cairo; using Gtk; using System.Linq; +using MonoDevelop.Components.AtkCocoaHelper; using MonoDevelop.Ide.Gui; using MonoDevelop.Ide.Fonts; @@ -73,6 +74,7 @@ namespace MonoDevelop.Components public Tabstrip () { + Accessible.SetRole (AtkCocoa.Roles.AXTabGroup); Events |= Gdk.EventMask.ButtonPressMask | Gdk.EventMask.PointerMotionMask | Gdk.EventMask.LeaveNotifyMask; } @@ -101,8 +103,31 @@ namespace MonoDevelop.Components else if (activeTab >= index) activeTab++; QueueResize (); + + tab.Allocation = GetBounds (tab); + Accessible.AddAccessibleElement (tab.Accessible); + tab.AccessibilityPressed += OnTabPressed; + + UpdateAccessibilityTabs (); } - + + void OnTabPressed (object sender, EventArgs args) + { + ActiveTab = tabs.IndexOf (sender); + } + + void UpdateAccessibilityTabs () + { + int i = 0; + var proxies = new AtkCocoaHelper.AccessibilityElementProxy [tabs.Count]; + foreach (var tab in tabs) { + proxies [i] = tab.Accessible; + i++; + } + + Accessible.SetTabs (proxies); + } + Cairo.Rectangle GetBounds (Tab tab) { if (tab == null) @@ -242,6 +267,23 @@ namespace MonoDevelop.Components get; set; } + + Cairo.Rectangle allocation; + public Cairo.Rectangle Allocation { + get { + return allocation; + } + + set { + allocation = value; + + Gdk.Rectangle gdkRect = new Gdk.Rectangle ((int)allocation.X, (int)allocation.Y, (int)allocation.Width, (int)allocation.Height); + Accessible.FrameInGtkParent = gdkRect; + // If Y != 0, then we need to flip the y axis + + Accessible.FrameInParent = gdkRect; + } + } public Tab (Tabstrip parent, string label) : this (parent, label, TabPosition.Left) { @@ -257,7 +299,9 @@ namespace MonoDevelop.Components if (layout != null) layout.Dispose (); } - + + public AtkCocoaHelper.AccessibilityElementProxy Accessible { get; private set; } + public Tab (Tabstrip parent, string label, TabPosition tabPosition) { //this.parent = parent; @@ -273,6 +317,11 @@ namespace MonoDevelop.Components w = SpacerWidth * 2; this.TabPosition = tabPosition; + + Accessible = AccessibilityElementProxy.ButtonElementProxy (); + Accessible.Title = label; + Accessible.GtkParent = parent; + Accessible.PerformPress += OnTabPressed; } public Cairo.PointD Size { @@ -336,7 +385,14 @@ namespace MonoDevelop.Components handler (this, e); } + void OnTabPressed (object sender, EventArgs e) + { + // Proxy the event to the tab bar so it can set this tab as active + AccessibilityPressed?.Invoke (this, e); + } + public event EventHandler Activated; + public event EventHandler AccessibilityPressed; } } |