5
// Lluis Sanchez <lluis@xamarin.com>
7
// Copyright (c) 2011 Xamarin Inc
9
// Permission is hereby granted, free of charge, to any person obtaining a copy
10
// of this software and associated documentation files (the "Software"), to deal
11
// in the Software without restriction, including without limitation the rights
12
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13
// copies of the Software, and to permit persons to whom the Software is
14
// furnished to do so, subject to the following conditions:
16
// The above copyright notice and this permission notice shall be included in
17
// all copies or substantial portions of the Software.
19
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
30
using System.Collections.Generic;
35
namespace Xwt.GtkBackend
37
public class WidgetBackend: IWidgetBackend, IGtkWidgetBackend
41
Gtk.Alignment alignment;
42
Gtk.EventBox eventBox;
43
IWidgetEventSink eventSink;
44
WidgetEvent enabledEvents;
51
public TransferDataSource CurrentDragData;
52
public Gdk.DragAction DestDragAction;
53
public Gdk.DragAction SourceDragAction;
54
public int DragDataRequests;
55
public TransferDataStore DragData;
56
public bool DragDataForMotion;
57
public Gtk.TargetEntry[] ValidDropTypes;
58
public Point LastDragPosition;
61
DragDropData dragDropInfo;
63
const WidgetEvent dragDropEvents = WidgetEvent.DragDropCheck | WidgetEvent.DragDrop | WidgetEvent.DragOver | WidgetEvent.DragOverCheck;
64
const WidgetEvent sizeCheckEvents = WidgetEvent.PreferredWidthCheck | WidgetEvent.PreferredHeightCheck | WidgetEvent.PreferredHeightForWidthCheck | WidgetEvent.PreferredWidthForHeightCheck;
66
void IBackend.InitializeBackend (object frontend)
68
this.frontend = (Widget) frontend;
71
void IWidgetBackend.Initialize (IWidgetEventSink sink)
77
public virtual void Initialize ()
81
public IWidgetEventSink EventSink {
82
get { return eventSink; }
85
public Widget Frontend {
86
get { return frontend; }
89
public object NativeWidget {
95
public Gtk.Widget Widget {
96
get { return widget; }
99
value.Visible = widget.Visible;
100
GtkEngine.ReplaceChild (widget, value);
106
public Gtk.Widget RootWidget {
108
return alignment ?? eventBox ?? (Gtk.Widget) Widget;
112
public virtual bool Visible {
113
get { return Widget.Visible; }
115
Widget.Visible = value;
116
if (alignment != null)
117
alignment.Visible = value;
118
if (eventBox != null)
119
eventBox.Visible = value;
123
public virtual bool Sensitive {
124
get { return Widget.Sensitive; }
126
Widget.Sensitive = value;
127
if (eventBox != null)
128
eventBox.Sensitive = value;
132
public bool CanGetFocus {
133
get { return Widget.CanFocus; }
134
set { Widget.CanFocus = value; }
137
public bool HasFocus {
138
get { return Widget.IsFocus; }
141
public void SetFocus ()
143
Widget.IsFocus = true;
146
public string TooltipText {
148
return Widget.TooltipText;
151
Widget.TooltipText = value;
155
static Dictionary<CursorType,Gdk.Cursor> gtkCursors = new Dictionary<CursorType, Gdk.Cursor> ();
157
public void SetCursor (CursorType cursor)
161
if (!gtkCursors.TryGetValue (cursor, out gc)) {
162
Gdk.CursorType ctype;
163
if (cursor == CursorType.Arrow)
164
ctype = Gdk.CursorType.LeftPtr;
165
else if (cursor == CursorType.Crosshair)
166
ctype = Gdk.CursorType.Crosshair;
167
else if (cursor == CursorType.Hand)
168
ctype = Gdk.CursorType.Hand1;
169
else if (cursor == CursorType.IBeam)
170
ctype = Gdk.CursorType.Xterm;
171
else if (cursor == CursorType.ResizeDown)
172
ctype = Gdk.CursorType.BottomSide;
173
else if (cursor == CursorType.ResizeUp)
174
ctype = Gdk.CursorType.TopSide;
175
else if (cursor == CursorType.ResizeLeft)
176
ctype = Gdk.CursorType.LeftSide;
177
else if (cursor == CursorType.ResizeRight)
178
ctype = Gdk.CursorType.RightSide;
179
else if (cursor == CursorType.ResizeLeftRight)
180
ctype = Gdk.CursorType.SbHDoubleArrow;
181
else if (cursor == CursorType.ResizeUpDown)
182
ctype = Gdk.CursorType.SbVDoubleArrow;
184
ctype = Gdk.CursorType.Arrow;
186
gtkCursors [cursor] = gc = new Gdk.Cursor (ctype);
188
if (EventsRootWidget.GdkWindow == null) {
189
EventHandler h = null;
191
EventsRootWidget.GdkWindow.Cursor = gc;
192
EventsRootWidget.Realized -= h;
194
EventsRootWidget.Realized += h;
196
EventsRootWidget.GdkWindow.Cursor = gc;
204
public void Dispose ()
206
GC.SuppressFinalize (this);
210
protected virtual void Dispose (bool disposing)
212
if (Widget != null && disposing && Widget.Parent == null && !destroyed) {
213
MarkDestroyed (Frontend);
218
void MarkDestroyed (Widget w)
220
var bk = (WidgetBackend) WidgetRegistry.GetBackend (w);
222
foreach (var c in w.Surface.Children)
228
return new Size (Widget.Allocation.Width, Widget.Allocation.Height);
232
DragDropData DragDropInfo {
234
if (dragDropInfo == null)
235
dragDropInfo = new DragDropData ();
240
public Point ConvertToScreenCoordinates (Point widgetCoordinates)
242
if (Widget.ParentWindow == null)
245
Widget.ParentWindow.GetOrigin (out x, out y);
246
var a = Widget.Allocation;
249
return new Point (x + widgetCoordinates.X, y + widgetCoordinates.Y);
252
public virtual WidgetSize GetPreferredWidth ()
254
bool oldFlag = doubleSizeRequestCheckSupported;
256
gettingPreferredSize = true;
257
doubleSizeRequestCheckSupported = false;
258
var s = new WidgetSize (Widget.SizeRequest ().Width);
259
if (minSizeSet && Frontend.MinWidth != -1)
260
s.MinSize = Frontend.MinWidth;
263
gettingPreferredSize = false;
264
doubleSizeRequestCheckSupported = oldFlag;
268
public virtual WidgetSize GetPreferredHeight ()
270
bool oldFlag = doubleSizeRequestCheckSupported;
272
gettingPreferredSize = true;
273
doubleSizeRequestCheckSupported = false;
274
var s = new WidgetSize (Widget.SizeRequest ().Height);
275
if (minSizeSet && Frontend.MinHeight != -1)
276
s.MinSize = Frontend.MinHeight;
279
gettingPreferredSize = false;
280
doubleSizeRequestCheckSupported = oldFlag;
284
public virtual WidgetSize GetPreferredHeightForWidth (double width)
286
bool oldFlag = doubleSizeRequestCheckSupported;
288
gettingPreferredSize = true;
289
doubleSizeRequestCheckSupported = false;
290
var s = new WidgetSize (Widget.SizeRequest ().Height);
291
if (minSizeSet && Frontend.MinHeight != -1)
292
s.MinSize = Frontend.MinHeight;
295
gettingPreferredSize = false;
296
doubleSizeRequestCheckSupported = oldFlag;
300
public virtual WidgetSize GetPreferredWidthForHeight (double height)
302
bool oldFlag = doubleSizeRequestCheckSupported;
304
gettingPreferredSize = true;
305
doubleSizeRequestCheckSupported = false;
306
var s = new WidgetSize (Widget.SizeRequest ().Width);
307
if (minSizeSet && Frontend.MinWidth != -1)
308
s.MinSize = Frontend.MinWidth;
311
gettingPreferredSize = false;
312
doubleSizeRequestCheckSupported = oldFlag;
316
public void SetMinSize (double width, double height)
318
if (width != -1 || height != -1) {
319
EnableSizeCheckEvents ();
324
DisableSizeCheckEvents ();
328
public void SetNaturalSize (double width, double height)
333
Pango.FontDescription customFont;
335
public virtual object Font {
337
return customFont ?? Widget.Style.FontDescription;
340
var fd = (Pango.FontDescription) value;
342
Widget.ModifyFont (fd);
346
Color? customBackgroundColor;
348
public virtual Color BackgroundColor {
350
return customBackgroundColor.HasValue ? customBackgroundColor.Value : Util.ToXwtColor (Widget.Style.Background (Gtk.StateType.Normal));
353
customBackgroundColor = value;
354
Widget.ModifyBg (Gtk.StateType.Normal, Util.ToGdkColor (value));
358
public bool UsingCustomBackgroundColor {
359
get { return customBackgroundColor.HasValue; }
362
Gtk.Widget IGtkWidgetBackend.Widget {
363
get { return RootWidget; }
366
protected virtual Gtk.Widget EventsRootWidget {
367
get { return eventBox ?? Widget; }
370
public static Gtk.Widget GetWidget (IWidgetBackend w)
372
return w != null ? ((IGtkWidgetBackend)w).Widget : null;
375
public virtual void UpdateLayout ()
377
if (frontend.Margin.HorizontalSpacing == 0 && frontend.Margin.VerticalSpacing == 0) {
378
if (alignment != null) {
379
alignment.Remove (alignment.Child);
380
GtkEngine.ReplaceChild (alignment, EventsRootWidget);
381
alignment.Destroy ();
385
if (alignment == null) {
386
alignment = new Gtk.Alignment (0, 0, 1, 1);
387
GtkEngine.ReplaceChild (EventsRootWidget, alignment);
388
alignment.Add (EventsRootWidget);
389
alignment.Visible = Widget.Visible;
391
alignment.LeftPadding = (uint) frontend.Margin.Left;
392
alignment.RightPadding = (uint) frontend.Margin.Right;
393
alignment.TopPadding = (uint) frontend.Margin.Top;
394
alignment.BottomPadding = (uint) frontend.Margin.Bottom;
396
Widget.QueueResize ();
398
if (!Widget.IsRealized) {
399
// This is a workaround to a GTK bug. When a widget is inside a ScrolledWindow, sometimes the QueueResize call on
400
// the widget is ignored if the widget is not realized.
401
var p = Widget.Parent;
402
while (p != null && !(p is Gtk.ScrolledWindow))
409
void AllocEventBox ()
411
// Wraps the widget with an event box. Required for some
412
// widgets such as Label which doesn't have its own gdk window
414
if (eventBox == null && EventsRootWidget.IsNoWindow) {
415
eventBox = new Gtk.EventBox ();
416
eventBox.Visible = Widget.Visible;
417
eventBox.Sensitive = Widget.Sensitive;
418
if (alignment != null) {
419
alignment.Remove (alignment.Child);
420
alignment.Add (eventBox);
422
GtkEngine.ReplaceChild (Widget, eventBox);
423
eventBox.Add (Widget);
427
public virtual void EnableEvent (object eventId)
429
if (eventId is WidgetEvent) {
430
WidgetEvent ev = (WidgetEvent) eventId;
432
case WidgetEvent.DragLeave:
434
EventsRootWidget.DragLeave += HandleWidgetDragLeave;
436
case WidgetEvent.DragStarted:
438
EventsRootWidget.DragBegin += HandleWidgetDragBegin;
440
case WidgetEvent.KeyPressed:
441
Widget.KeyPressEvent += HandleKeyPressEvent;
443
case WidgetEvent.KeyReleased:
444
Widget.KeyReleaseEvent += HandleKeyReleaseEvent;
446
case WidgetEvent.GotFocus:
447
EventsRootWidget.Events |= Gdk.EventMask.FocusChangeMask;
448
Widget.FocusGrabbed += HandleWidgetFocusInEvent;
450
case WidgetEvent.LostFocus:
451
EventsRootWidget.Events |= Gdk.EventMask.FocusChangeMask;
452
Widget.FocusOutEvent += HandleWidgetFocusOutEvent;
454
case WidgetEvent.MouseEntered:
456
EventsRootWidget.Events |= Gdk.EventMask.EnterNotifyMask;
457
EventsRootWidget.EnterNotifyEvent += HandleEnterNotifyEvent;
459
case WidgetEvent.MouseExited:
461
EventsRootWidget.Events |= Gdk.EventMask.LeaveNotifyMask;
462
EventsRootWidget.LeaveNotifyEvent += HandleLeaveNotifyEvent;
464
case WidgetEvent.ButtonPressed:
466
EventsRootWidget.Events |= Gdk.EventMask.ButtonPressMask;
467
EventsRootWidget.ButtonPressEvent += HandleButtonPressEvent;
469
case WidgetEvent.ButtonReleased:
471
EventsRootWidget.Events |= Gdk.EventMask.ButtonReleaseMask;
472
EventsRootWidget.ButtonReleaseEvent += HandleButtonReleaseEvent;
474
case WidgetEvent.MouseMoved:
476
EventsRootWidget.Events |= Gdk.EventMask.PointerMotionMask;
477
EventsRootWidget.MotionNotifyEvent += HandleMotionNotifyEvent;
479
case WidgetEvent.BoundsChanged:
480
Widget.SizeAllocated += HandleWidgetBoundsChanged;
482
case WidgetEvent.MouseScrolled:
484
EventsRootWidget.Events |= Gdk.EventMask.ScrollMask;
485
Widget.ScrollEvent += HandleScrollEvent;
488
if ((ev & dragDropEvents) != 0 && (enabledEvents & dragDropEvents) == 0) {
489
// Enabling a drag&drop event for the first time
491
EventsRootWidget.DragDrop += HandleWidgetDragDrop;
492
EventsRootWidget.DragMotion += HandleWidgetDragMotion;
493
EventsRootWidget.DragDataReceived += HandleWidgetDragDataReceived;
495
if ((ev & sizeCheckEvents) != 0) {
496
EnableSizeCheckEvents ();
502
void EnableSizeCheckEvents ()
504
if ((enabledEvents & sizeCheckEvents) == 0 && !minSizeSet) {
505
// Enabling a size request event for the first time
506
Widget.SizeRequested += HandleWidgetSizeRequested;
507
Widget.SizeAllocated += HandleWidgetSizeAllocated;;
511
public virtual void DisableEvent (object eventId)
513
if (eventId is WidgetEvent) {
514
WidgetEvent ev = (WidgetEvent) eventId;
516
case WidgetEvent.DragLeave:
517
EventsRootWidget.DragLeave -= HandleWidgetDragLeave;
519
case WidgetEvent.DragStarted:
520
EventsRootWidget.DragBegin -= HandleWidgetDragBegin;
522
case WidgetEvent.KeyPressed:
523
Widget.KeyPressEvent -= HandleKeyPressEvent;
525
case WidgetEvent.KeyReleased:
526
Widget.KeyReleaseEvent -= HandleKeyReleaseEvent;
528
case WidgetEvent.GotFocus:
529
Widget.FocusInEvent -= HandleWidgetFocusInEvent;
531
case WidgetEvent.LostFocus:
532
Widget.FocusOutEvent -= HandleWidgetFocusOutEvent;
534
case WidgetEvent.MouseEntered:
535
EventsRootWidget.EnterNotifyEvent -= HandleEnterNotifyEvent;
537
case WidgetEvent.MouseExited:
538
EventsRootWidget.LeaveNotifyEvent -= HandleLeaveNotifyEvent;
540
case WidgetEvent.ButtonPressed:
541
EventsRootWidget.Events &= ~Gdk.EventMask.ButtonPressMask;
542
EventsRootWidget.ButtonPressEvent -= HandleButtonPressEvent;
544
case WidgetEvent.ButtonReleased:
545
EventsRootWidget.Events &= Gdk.EventMask.ButtonReleaseMask;
546
EventsRootWidget.ButtonReleaseEvent -= HandleButtonReleaseEvent;
548
case WidgetEvent.MouseMoved:
549
EventsRootWidget.Events &= Gdk.EventMask.PointerMotionMask;
550
EventsRootWidget.MotionNotifyEvent -= HandleMotionNotifyEvent;
552
case WidgetEvent.BoundsChanged:
553
Widget.SizeAllocated -= HandleWidgetBoundsChanged;
555
case WidgetEvent.MouseScrolled:
556
EventsRootWidget.Events &= ~Gdk.EventMask.ScrollMask;
557
Widget.ScrollEvent -= HandleScrollEvent;
561
enabledEvents &= ~ev;
563
if ((ev & dragDropEvents) != 0 && (enabledEvents & dragDropEvents) == 0) {
564
// All drag&drop events have been disabled
565
EventsRootWidget.DragDrop -= HandleWidgetDragDrop;
566
EventsRootWidget.DragMotion -= HandleWidgetDragMotion;
567
EventsRootWidget.DragDataReceived -= HandleWidgetDragDataReceived;
569
if ((ev & sizeCheckEvents) != 0) {
570
DisableSizeCheckEvents ();
572
if ((ev & WidgetEvent.GotFocus) == 0 && (enabledEvents & WidgetEvent.LostFocus) == 0) {
573
EventsRootWidget.Events &= ~Gdk.EventMask.FocusChangeMask;
578
void DisableSizeCheckEvents ()
580
if ((enabledEvents & sizeCheckEvents) == 0 && !minSizeSet) {
581
// All size request events have been disabled
582
Widget.SizeRequested -= HandleWidgetSizeRequested;
583
Widget.SizeAllocated -= HandleWidgetSizeAllocated;;
587
Gdk.Rectangle lastAllocation;
588
void HandleWidgetBoundsChanged (object o, Gtk.SizeAllocatedArgs args)
590
if (Widget.Allocation != lastAllocation) {
591
lastAllocation = Widget.Allocation;
592
Toolkit.Invoke (delegate {
593
EventSink.OnBoundsChanged ();
606
SizeCheckStep sizeCheckStep = SizeCheckStep.SizeRequest;
607
int realRequestedWidth;
608
int realRequestedHeight;
609
bool gettingPreferredSize;
610
static bool doubleSizeRequestCheckSupported = true;
612
public bool IsPreallocating {
613
get { return sizeCheckStep == SizeCheckStep.AdjustSize || sizeCheckStep == SizeCheckStep.PreAllocate; }
616
void HandleWidgetSizeRequested (object o, Gtk.SizeRequestedArgs args)
618
if (gettingPreferredSize)
621
var req = args.Requisition;
623
if ((enabledEvents & sizeCheckEvents) == 0) {
624
// If no sizing event is set, it means this handler was set because there is a min size.
625
if (Frontend.MinWidth != -1)
626
req.Width = (int) Frontend.MinWidth;
627
if (Frontend.MinHeight != -1)
628
req.Height = (int) Frontend.MinHeight;
632
if (sizeCheckStep == SizeCheckStep.AdjustSize) {
633
req.Width = realRequestedWidth;
634
req.Height = realRequestedHeight;
635
sizeCheckStep = SizeCheckStep.FinalAllocate;
638
Toolkit.Invoke (delegate {
639
if (EventSink.GetSizeRequestMode () == SizeRequestMode.HeightForWidth) {
640
if ((enabledEvents & WidgetEvent.PreferredWidthCheck) != 0) {
641
var w = eventSink.OnGetPreferredWidth ();
642
req.Width = (int) w.MinSize;
644
if ((enabledEvents & WidgetEvent.PreferredHeightForWidthCheck) != 0) {
645
if (doubleSizeRequestCheckSupported) {
646
sizeCheckStep = SizeCheckStep.PreAllocate;
647
realRequestedWidth = req.Width; // Store the width, since it will be used in the next iteration
649
var h = eventSink.OnGetPreferredHeightForWidth (req.Width);
650
req.Height = (int) h.MinSize;
651
sizeCheckStep = SizeCheckStep.FinalAllocate;
654
else if ((enabledEvents & WidgetEvent.PreferredHeightCheck) != 0) {
655
var h = eventSink.OnGetPreferredHeight ();
656
req.Height = (int) h.MinSize;
657
sizeCheckStep = SizeCheckStep.FinalAllocate;
660
if ((enabledEvents & WidgetEvent.PreferredHeightCheck) != 0) {
661
var h = eventSink.OnGetPreferredHeight ();
662
req.Height = (int) h.MinSize;
664
if ((enabledEvents & WidgetEvent.PreferredWidthForHeightCheck) != 0) {
665
if (doubleSizeRequestCheckSupported) {
666
sizeCheckStep = SizeCheckStep.PreAllocate;
667
realRequestedHeight = req.Height; // Store the height, since it will be used in the next iteration
669
var w = eventSink.OnGetPreferredWidthForHeight (req.Height);
670
req.Width = (int) w.MinSize;
671
sizeCheckStep = SizeCheckStep.FinalAllocate;
674
else if ((enabledEvents & WidgetEvent.PreferredWidthCheck) != 0) {
675
var w = eventSink.OnGetPreferredWidth ();
676
req.Width = (int) w.MinSize;
677
sizeCheckStep = SizeCheckStep.FinalAllocate;
682
args.Requisition = req;
685
void HandleWidgetSizeAllocated (object o, Gtk.SizeAllocatedArgs args)
687
if ((enabledEvents & sizeCheckEvents) == 0) {
688
// If no sizing event is set, it means this handler was set because there is a min size.
689
// In that case, there isn't any thing left to do here
693
Toolkit.Invoke (delegate {
694
if (sizeCheckStep == SizeCheckStep.SizeRequest && (enabledEvents & sizeCheckEvents) != sizeCheckEvents) {
695
var ev = EventSink.GetSizeRequestMode () == SizeRequestMode.HeightForWidth ? WidgetEvent.PreferredWidthCheck | WidgetEvent.PreferredHeightForWidthCheck : WidgetEvent.PreferredHeightCheck | WidgetEvent.PreferredWidthForHeightCheck;
696
// If all size request methods are overriden, the widget's size request won't be called, so this status is correct
697
if ((enabledEvents & ev) != ev)
698
Console.WriteLine ("SizeRequest not called. Should not happen.");
700
else if (sizeCheckStep == SizeCheckStep.PreAllocate || sizeCheckStep == SizeCheckStep.AdjustSize) {
701
if (EventSink.GetSizeRequestMode () == SizeRequestMode.HeightForWidth) {
702
realRequestedHeight = (int) eventSink.OnGetPreferredHeightForWidth (args.Allocation.Width).MinSize;
703
sizeCheckStep = SizeCheckStep.AdjustSize;
704
Widget.QueueResize ();
706
realRequestedWidth = (int) eventSink.OnGetPreferredWidthForHeight (args.Allocation.Height).MinSize;
707
sizeCheckStep = SizeCheckStep.AdjustSize;
708
Widget.QueueResize ();
715
void HandleKeyReleaseEvent (object o, Gtk.KeyReleaseEventArgs args)
717
Key k = (Key)args.Event.KeyValue;
718
ModifierKeys m = ModifierKeys.None;
719
if ((args.Event.State & Gdk.ModifierType.ShiftMask) != 0)
720
m |= ModifierKeys.Shift;
721
if ((args.Event.State & Gdk.ModifierType.ControlMask) != 0)
722
m |= ModifierKeys.Control;
723
if ((args.Event.State & Gdk.ModifierType.Mod1Mask) != 0)
724
m |= ModifierKeys.Alt;
725
KeyEventArgs kargs = new KeyEventArgs (k, m, false, (long)args.Event.Time);
726
Toolkit.Invoke (delegate {
727
EventSink.OnKeyReleased (kargs);
734
void HandleKeyPressEvent (object o, Gtk.KeyPressEventArgs args)
736
Key k = (Key)args.Event.KeyValue;
737
ModifierKeys m = ModifierKeys.None;
738
if ((args.Event.State & Gdk.ModifierType.ShiftMask) != 0)
739
m |= ModifierKeys.Shift;
740
if ((args.Event.State & Gdk.ModifierType.ControlMask) != 0)
741
m |= ModifierKeys.Control;
742
if ((args.Event.State & Gdk.ModifierType.Mod1Mask) != 0)
743
m |= ModifierKeys.Alt;
744
KeyEventArgs kargs = new KeyEventArgs (k, m, false, (long)args.Event.Time);
745
Toolkit.Invoke (delegate {
746
EventSink.OnKeyPressed (kargs);
753
void HandleScrollEvent(object o, Gtk.ScrollEventArgs args)
755
var sc = ConvertToScreenCoordinates (new Point (0, 0));
756
var direction = Util.ConvertScrollDirection(args.Event.Direction);
758
var a = new MouseScrolledEventArgs ((long) args.Event.Time, args.Event.XRoot - sc.X, args.Event.YRoot - sc.Y, direction);
759
Toolkit.Invoke (delegate {
760
EventSink.OnMouseScrolled(a);
767
void HandleWidgetFocusOutEvent (object o, Gtk.FocusOutEventArgs args)
769
Toolkit.Invoke (delegate {
770
EventSink.OnLostFocus ();
774
void HandleWidgetFocusInEvent (object o, EventArgs args)
776
Toolkit.Invoke (delegate {
777
EventSink.OnGotFocus ();
781
void HandleLeaveNotifyEvent (object o, Gtk.LeaveNotifyEventArgs args)
783
if (args.Event.Detail == Gdk.NotifyType.Inferior)
785
Toolkit.Invoke (delegate {
786
EventSink.OnMouseExited ();
790
void HandleEnterNotifyEvent (object o, Gtk.EnterNotifyEventArgs args)
792
if (args.Event.Detail == Gdk.NotifyType.Inferior)
794
Toolkit.Invoke (delegate {
795
EventSink.OnMouseEntered ();
799
void HandleMotionNotifyEvent (object o, Gtk.MotionNotifyEventArgs args)
801
var sc = ConvertToScreenCoordinates (new Point (0, 0));
802
var a = new MouseMovedEventArgs ((long) args.Event.Time, args.Event.XRoot - sc.X, args.Event.YRoot - sc.Y);
803
Toolkit.Invoke (delegate {
804
EventSink.OnMouseMoved (a);
810
void HandleButtonReleaseEvent (object o, Gtk.ButtonReleaseEventArgs args)
812
var sc = ConvertToScreenCoordinates (new Point (0, 0));
813
var a = new ButtonEventArgs ();
814
a.X = args.Event.XRoot - sc.X;
815
a.Y = args.Event.YRoot - sc.Y;
816
a.Button = (PointerButton) args.Event.Button;
817
Toolkit.Invoke (delegate {
818
EventSink.OnButtonReleased (a);
824
[GLib.ConnectBeforeAttribute]
825
void HandleButtonPressEvent (object o, Gtk.ButtonPressEventArgs args)
827
var sc = ConvertToScreenCoordinates (new Point (0, 0));
828
var a = new ButtonEventArgs ();
829
a.X = args.Event.XRoot - sc.X;
830
a.Y = args.Event.YRoot - sc.Y;
831
a.Button = (PointerButton) args.Event.Button;
832
if (args.Event.Type == Gdk.EventType.TwoButtonPress)
834
else if (args.Event.Type == Gdk.EventType.ThreeButtonPress)
838
Toolkit.Invoke (delegate {
839
EventSink.OnButtonPressed (a);
846
void HandleWidgetDragMotion (object o, Gtk.DragMotionArgs args)
848
args.RetVal = DoDragMotion (args.Context, args.X, args.Y, args.Time);
851
internal bool DoDragMotion (Gdk.DragContext context, int x, int y, uint time)
853
DragDropInfo.LastDragPosition = new Point (x, y);
856
if ((enabledEvents & WidgetEvent.DragOverCheck) == 0) {
857
if ((enabledEvents & WidgetEvent.DragOver) != 0)
858
ac = DragDropAction.Default;
860
ac = ConvertDragAction (DragDropInfo.DestDragAction);
863
// This is a workaround to what seems to be a mac gtk bug.
864
// Suggested action is set to all when no control key is pressed
865
var cact = ConvertDragAction (context.Actions);
866
if (cact == DragDropAction.All)
867
cact = DragDropAction.Move;
869
var target = Gtk.Drag.DestFindTarget (EventsRootWidget, context, null);
870
var targetTypes = Util.GetDragTypes (new Gdk.Atom[] { target });
871
DragOverCheckEventArgs da = new DragOverCheckEventArgs (new Point (x, y), targetTypes, cact);
872
Toolkit.Invoke (delegate {
873
EventSink.OnDragOverCheck (da);
875
ac = da.AllowedAction;
876
if ((enabledEvents & WidgetEvent.DragOver) == 0 && ac == DragDropAction.Default)
877
ac = DragDropAction.None;
880
if (ac == DragDropAction.None) {
881
OnSetDragStatus (context, x, y, time, (Gdk.DragAction)0);
884
else if (ac == DragDropAction.Default) {
885
// Undefined, we need more data
886
QueryDragData (context, time, true);
890
// Gtk.Drag.Highlight (Widget);
891
OnSetDragStatus (context, x, y, time, ConvertDragAction (ac));
897
void HandleWidgetDragDrop (object o, Gtk.DragDropArgs args)
899
args.RetVal = DoDragDrop (args.Context, args.X, args.Y, args.Time);
902
internal bool DoDragDrop (Gdk.DragContext context, int x, int y, uint time)
904
DragDropInfo.LastDragPosition = new Point (x, y);
905
var cda = ConvertDragAction (context.Action);
908
if ((enabledEvents & WidgetEvent.DragDropCheck) == 0) {
909
if ((enabledEvents & WidgetEvent.DragDrop) != 0)
910
res = DragDropResult.None;
912
res = DragDropResult.Canceled;
915
DragCheckEventArgs da = new DragCheckEventArgs (new Point (x, y), Util.GetDragTypes (context.Targets), cda);
916
Toolkit.Invoke (delegate {
917
EventSink.OnDragDropCheck (da);
920
if ((enabledEvents & WidgetEvent.DragDrop) == 0 && res == DragDropResult.None)
921
res = DragDropResult.Canceled;
923
if (res == DragDropResult.Canceled) {
924
Gtk.Drag.Finish (context, false, false, time);
927
else if (res == DragDropResult.Success) {
928
Gtk.Drag.Finish (context, true, cda == DragDropAction.Move, time);
932
// Undefined, we need more data
933
QueryDragData (context, time, false);
938
void HandleWidgetDragLeave (object o, Gtk.DragLeaveArgs args)
940
Toolkit.Invoke (delegate {
941
eventSink.OnDragLeave (EventArgs.Empty);
945
void QueryDragData (Gdk.DragContext ctx, uint time, bool isMotionEvent)
947
DragDropInfo.DragDataForMotion = isMotionEvent;
948
DragDropInfo.DragData = new TransferDataStore ();
949
DragDropInfo.DragDataRequests = DragDropInfo.ValidDropTypes.Length;
950
foreach (var t in DragDropInfo.ValidDropTypes) {
951
var at = Gdk.Atom.Intern (t.Target, true);
952
Gtk.Drag.GetData (EventsRootWidget, ctx, at, time);
956
void HandleWidgetDragDataReceived (object o, Gtk.DragDataReceivedArgs args)
958
args.RetVal = DoDragDataReceived (args.Context, args.X, args.Y, args.SelectionData, args.Info, args.Time);
961
internal bool DoDragDataReceived (Gdk.DragContext context, int x, int y, Gtk.SelectionData selectionData, uint info, uint time)
963
if (DragDropInfo.DragDataRequests == 0) {
964
// Got the data without requesting it. Create the datastore here
965
DragDropInfo.DragData = new TransferDataStore ();
966
DragDropInfo.LastDragPosition = new Point (x, y);
967
DragDropInfo.DragDataRequests = 1;
970
DragDropInfo.DragDataRequests--;
972
if (!Util.GetSelectionData (selectionData, DragDropInfo.DragData)) {
976
if (DragDropInfo.DragDataRequests == 0) {
977
if (DragDropInfo.DragDataForMotion) {
978
// If no specific action is set, it means that no key has been pressed.
979
// In that case, use Move or Copy or Link as default (when allowed, in this order).
980
var cact = ConvertDragAction (context.Actions);
981
if (cact != DragDropAction.Copy && cact != DragDropAction.Move && cact != DragDropAction.Link) {
982
if (cact.HasFlag (DragDropAction.Move))
983
cact = DragDropAction.Move;
984
else if (cact.HasFlag (DragDropAction.Copy))
985
cact = DragDropAction.Copy;
986
else if (cact.HasFlag (DragDropAction.Link))
987
cact = DragDropAction.Link;
989
cact = DragDropAction.None;
992
DragOverEventArgs da = new DragOverEventArgs (DragDropInfo.LastDragPosition, DragDropInfo.DragData, cact);
993
Toolkit.Invoke (delegate {
994
EventSink.OnDragOver (da);
996
OnSetDragStatus (context, (int)DragDropInfo.LastDragPosition.X, (int)DragDropInfo.LastDragPosition.Y, time, ConvertDragAction (da.AllowedAction));
1000
// Use Context.Action here since that's the action selected in DragOver
1001
var cda = ConvertDragAction (context.Action);
1002
DragEventArgs da = new DragEventArgs (DragDropInfo.LastDragPosition, DragDropInfo.DragData, cda);
1003
Toolkit.Invoke (delegate {
1004
EventSink.OnDragDrop (da);
1006
Gtk.Drag.Finish (context, da.Success, cda == DragDropAction.Move, time);
1013
protected virtual void OnSetDragStatus (Gdk.DragContext context, int x, int y, uint time, Gdk.DragAction action)
1015
Gdk.Drag.Status (context, action, time);
1018
void HandleWidgetDragBegin (object o, Gtk.DragBeginArgs args)
1020
// If SetDragSource has not been called, ignore the event
1021
if (DragDropInfo.SourceDragAction == default (Gdk.DragAction))
1024
DragStartData sdata = null;
1025
Toolkit.Invoke (delegate {
1026
sdata = EventSink.OnDragStarted ();
1032
DragDropInfo.CurrentDragData = sdata.Data;
1034
if (sdata.ImageBackend != null)
1035
Gtk.Drag.SetIconPixbuf (args.Context, (Gdk.Pixbuf) sdata.ImageBackend, (int)sdata.HotX, (int)sdata.HotY);
1037
HandleDragBegin (null, args);
1040
class IconInitializer
1042
public Gdk.Pixbuf Image;
1043
public double HotX, HotY;
1044
public Gtk.Widget Widget;
1046
public static void Init (Gtk.Widget w, Gdk.Pixbuf image, double hotX, double hotY)
1048
IconInitializer ii = new WidgetBackend.IconInitializer ();
1053
w.DragBegin += ii.Begin;
1056
void Begin (object o, Gtk.DragBeginArgs args)
1058
Gtk.Drag.SetIconPixbuf (args.Context, Image, (int)HotX, (int)HotY);
1059
Widget.DragBegin -= Begin;
1063
public void DragStart (DragStartData sdata)
1066
Gdk.DragAction action = ConvertDragAction (sdata.DragAction);
1067
DragDropInfo.CurrentDragData = sdata.Data;
1068
EventsRootWidget.DragBegin += HandleDragBegin;
1069
if (sdata.ImageBackend != null)
1070
IconInitializer.Init (EventsRootWidget, (Gdk.Pixbuf) sdata.ImageBackend, sdata.HotX, sdata.HotY);
1071
Gtk.Drag.Begin (EventsRootWidget, Util.BuildTargetTable (sdata.Data.DataTypes), action, 1, Gtk.Global.CurrentEvent);
1074
void HandleDragBegin (object o, Gtk.DragBeginArgs args)
1076
EventsRootWidget.DragEnd += HandleWidgetDragEnd;
1077
EventsRootWidget.DragFailed += HandleDragFailed;
1078
EventsRootWidget.DragDataDelete += HandleDragDataDelete;
1079
EventsRootWidget.DragDataGet += HandleWidgetDragDataGet;
1082
void HandleWidgetDragDataGet (object o, Gtk.DragDataGetArgs args)
1084
Util.SetDragData (DragDropInfo.CurrentDragData, args);
1087
void HandleDragFailed (object o, Gtk.DragFailedArgs args)
1089
Console.WriteLine ("FAILED");
1092
void HandleDragDataDelete (object o, Gtk.DragDataDeleteArgs args)
1094
DoDragaDataDelete ();
1097
internal void DoDragaDataDelete ()
1102
void HandleWidgetDragEnd (object o, Gtk.DragEndArgs args)
1107
void FinishDrag (bool delete)
1109
EventsRootWidget.DragEnd -= HandleWidgetDragEnd;
1110
EventsRootWidget.DragDataGet -= HandleWidgetDragDataGet;
1111
EventsRootWidget.DragFailed -= HandleDragFailed;
1112
EventsRootWidget.DragDataDelete -= HandleDragDataDelete;
1113
EventsRootWidget.DragBegin -= HandleDragBegin; // This event is subscribed only when manualy starting a drag
1114
Toolkit.Invoke (delegate {
1115
eventSink.OnDragFinished (new DragFinishedEventArgs (delete));
1119
public void SetDragTarget (TransferDataType[] types, DragDropAction dragAction)
1121
DragDropInfo.DestDragAction = ConvertDragAction (dragAction);
1122
var table = Util.BuildTargetTable (types);
1123
DragDropInfo.ValidDropTypes = (Gtk.TargetEntry[]) table;
1124
OnSetDragTarget (DragDropInfo.ValidDropTypes, DragDropInfo.DestDragAction);
1127
protected virtual void OnSetDragTarget (Gtk.TargetEntry[] table, Gdk.DragAction actions)
1130
Gtk.Drag.DestSet (EventsRootWidget, Gtk.DestDefaults.Highlight, table, actions);
1133
public void SetDragSource (TransferDataType[] types, DragDropAction dragAction)
1136
DragDropInfo.SourceDragAction = ConvertDragAction (dragAction);
1137
var table = Util.BuildTargetTable (types);
1138
OnSetDragSource (Gdk.ModifierType.Button1Mask, (Gtk.TargetEntry[]) table, DragDropInfo.SourceDragAction);
1141
protected virtual void OnSetDragSource (Gdk.ModifierType modifierType, Gtk.TargetEntry[] table, Gdk.DragAction actions)
1143
Gtk.Drag.SourceSet (EventsRootWidget, modifierType, table, actions);
1146
Gdk.DragAction ConvertDragAction (DragDropAction dragAction)
1148
Gdk.DragAction action = (Gdk.DragAction)0;
1149
if ((dragAction & DragDropAction.Copy) != 0)
1150
action |= Gdk.DragAction.Copy;
1151
if ((dragAction & DragDropAction.Move) != 0)
1152
action |= Gdk.DragAction.Move;
1153
if ((dragAction & DragDropAction.Link) != 0)
1154
action |= Gdk.DragAction.Link;
1158
DragDropAction ConvertDragAction (Gdk.DragAction dragAction)
1160
DragDropAction action = (DragDropAction)0;
1161
if ((dragAction & Gdk.DragAction.Copy) != 0)
1162
action |= DragDropAction.Copy;
1163
if ((dragAction & Gdk.DragAction.Move) != 0)
1164
action |= DragDropAction.Move;
1165
if ((dragAction & Gdk.DragAction.Link) != 0)
1166
action |= DragDropAction.Link;
1171
public interface IGtkWidgetBackend
1173
Gtk.Widget Widget { get; }