1 /* 2 * This file is part of gtkD. 3 * 4 * gtkD is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU Lesser General Public License 6 * as published by the Free Software Foundation; either version 3 7 * of the License, or (at your option) any later version, with 8 * some exceptions, please read the COPYING file. 9 * 10 * gtkD is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU Lesser General Public License for more details. 14 * 15 * You should have received a copy of the GNU Lesser General Public License 16 * along with gtkD; if not, write to the Free Software 17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA 18 */ 19 20 // generated automatically - do not change 21 // find conversion definition on APILookup.txt 22 // implement new conversion functionalities on the wrap.utils pakage 23 24 25 module gtk.Gesture; 26 27 private import gdk.Device; 28 private import gdk.Event; 29 private import gdk.Window; 30 private import glib.ListG; 31 private import gobject.ObjectG; 32 private import gobject.Signals; 33 private import gtk.EventController; 34 private import gtk.c.functions; 35 public import gtk.c.types; 36 public import gtkc.gtktypes; 37 private import std.algorithm; 38 39 40 /** 41 * #GtkGesture is the base object for gesture recognition, although this 42 * object is quite generalized to serve as a base for multi-touch gestures, 43 * it is suitable to implement single-touch and pointer-based gestures (using 44 * the special %NULL #GdkEventSequence value for these). 45 * 46 * The number of touches that a #GtkGesture need to be recognized is controlled 47 * by the #GtkGesture:n-points property, if a gesture is keeping track of less 48 * or more than that number of sequences, it won't check wether the gesture 49 * is recognized. 50 * 51 * As soon as the gesture has the expected number of touches, the gesture will 52 * run the #GtkGesture::check signal regularly on input events until the gesture 53 * is recognized, the criteria to consider a gesture as "recognized" is left to 54 * #GtkGesture subclasses. 55 * 56 * A recognized gesture will then emit the following signals: 57 * - #GtkGesture::begin when the gesture is recognized. 58 * - A number of #GtkGesture::update, whenever an input event is processed. 59 * - #GtkGesture::end when the gesture is no longer recognized. 60 * 61 * ## Event propagation 62 * 63 * In order to receive events, a gesture needs to either set a propagation phase 64 * through gtk_event_controller_set_propagation_phase(), or feed those manually 65 * through gtk_event_controller_handle_event(). 66 * 67 * In the capture phase, events are propagated from the toplevel down to the 68 * target widget, and gestures that are attached to containers above the widget 69 * get a chance to interact with the event before it reaches the target. 70 * 71 * After the capture phase, GTK+ emits the traditional #GtkWidget::button-press-event, 72 * #GtkWidget::button-release-event, #GtkWidget::touch-event, etc signals. Gestures 73 * with the %GTK_PHASE_TARGET phase are fed events from the default #GtkWidget::event 74 * handlers. 75 * 76 * In the bubble phase, events are propagated up from the target widget to the 77 * toplevel, and gestures that are attached to containers above the widget get 78 * a chance to interact with events that have not been handled yet. 79 * 80 * ## States of a sequence # {#touch-sequence-states} 81 * 82 * Whenever input interaction happens, a single event may trigger a cascade of 83 * #GtkGestures, both across the parents of the widget receiving the event and 84 * in parallel within an individual widget. It is a responsibility of the 85 * widgets using those gestures to set the state of touch sequences accordingly 86 * in order to enable cooperation of gestures around the #GdkEventSequences 87 * triggering those. 88 * 89 * Within a widget, gestures can be grouped through gtk_gesture_group(), 90 * grouped gestures synchronize the state of sequences, so calling 91 * gtk_gesture_set_sequence_state() on one will effectively propagate 92 * the state throughout the group. 93 * 94 * By default, all sequences start out in the #GTK_EVENT_SEQUENCE_NONE state, 95 * sequences in this state trigger the gesture event handler, but event 96 * propagation will continue unstopped by gestures. 97 * 98 * If a sequence enters into the #GTK_EVENT_SEQUENCE_DENIED state, the gesture 99 * group will effectively ignore the sequence, letting events go unstopped 100 * through the gesture, but the "slot" will still remain occupied while 101 * the touch is active. 102 * 103 * If a sequence enters in the #GTK_EVENT_SEQUENCE_CLAIMED state, the gesture 104 * group will grab all interaction on the sequence, by: 105 * - Setting the same sequence to #GTK_EVENT_SEQUENCE_DENIED on every other gesture 106 * group within the widget, and every gesture on parent widgets in the propagation 107 * chain. 108 * - calling #GtkGesture::cancel on every gesture in widgets underneath in the 109 * propagation chain. 110 * - Stopping event propagation after the gesture group handles the event. 111 * 112 * Note: if a sequence is set early to #GTK_EVENT_SEQUENCE_CLAIMED on 113 * #GDK_TOUCH_BEGIN/#GDK_BUTTON_PRESS (so those events are captured before 114 * reaching the event widget, this implies #GTK_PHASE_CAPTURE), one similar 115 * event will emulated if the sequence changes to #GTK_EVENT_SEQUENCE_DENIED. 116 * This way event coherence is preserved before event propagation is unstopped 117 * again. 118 * 119 * Sequence states can't be changed freely, see gtk_gesture_set_sequence_state() 120 * to know about the possible lifetimes of a #GdkEventSequence. 121 * 122 * ## Touchpad gestures 123 * 124 * On the platforms that support it, #GtkGesture will handle transparently 125 * touchpad gesture events. The only precautions users of #GtkGesture should do 126 * to enable this support are: 127 * - Enabling %GDK_TOUCHPAD_GESTURE_MASK on their #GdkWindows 128 * - If the gesture has %GTK_PHASE_NONE, ensuring events of type 129 * %GDK_TOUCHPAD_SWIPE and %GDK_TOUCHPAD_PINCH are handled by the #GtkGesture 130 */ 131 public class Gesture : EventController 132 { 133 /** the main Gtk struct */ 134 protected GtkGesture* gtkGesture; 135 136 /** Get the main Gtk struct */ 137 public GtkGesture* getGestureStruct(bool transferOwnership = false) 138 { 139 if (transferOwnership) 140 ownedRef = false; 141 return gtkGesture; 142 } 143 144 /** the main Gtk struct as a void* */ 145 protected override void* getStruct() 146 { 147 return cast(void*)gtkGesture; 148 } 149 150 protected override void setStruct(GObject* obj) 151 { 152 gtkGesture = cast(GtkGesture*)obj; 153 super.setStruct(obj); 154 } 155 156 /** 157 * Sets our main struct and passes it to the parent class. 158 */ 159 public this (GtkGesture* gtkGesture, bool ownedRef = false) 160 { 161 this.gtkGesture = gtkGesture; 162 super(cast(GtkEventController*)gtkGesture, ownedRef); 163 } 164 165 166 /** */ 167 public static GType getType() 168 { 169 return gtk_gesture_get_type(); 170 } 171 172 /** 173 * If there are touch sequences being currently handled by @gesture, 174 * this function returns %TRUE and fills in @rect with the bounding 175 * box containing all active touches. Otherwise, %FALSE will be 176 * returned. 177 * 178 * Note: This function will yield unexpected results on touchpad 179 * gestures. Since there is no correlation between physical and 180 * pixel distances, these will look as if constrained in an 181 * infinitely small area, @rect width and height will thus be 0 182 * regardless of the number of touchpoints. 183 * 184 * Params: 185 * rect = bounding box containing all active touches. 186 * 187 * Returns: %TRUE if there are active touches, %FALSE otherwise 188 * 189 * Since: 3.14 190 */ 191 public bool getBoundingBox(out GdkRectangle rect) 192 { 193 return gtk_gesture_get_bounding_box(gtkGesture, &rect) != 0; 194 } 195 196 /** 197 * If there are touch sequences being currently handled by @gesture, 198 * this function returns %TRUE and fills in @x and @y with the center 199 * of the bounding box containing all active touches. Otherwise, %FALSE 200 * will be returned. 201 * 202 * Params: 203 * x = X coordinate for the bounding box center 204 * y = Y coordinate for the bounding box center 205 * 206 * Returns: %FALSE if no active touches are present, %TRUE otherwise 207 * 208 * Since: 3.14 209 */ 210 public bool getBoundingBoxCenter(out double x, out double y) 211 { 212 return gtk_gesture_get_bounding_box_center(gtkGesture, &x, &y) != 0; 213 } 214 215 /** 216 * Returns the master #GdkDevice that is currently operating 217 * on @gesture, or %NULL if the gesture is not being interacted. 218 * 219 * Returns: a #GdkDevice, or %NULL 220 * 221 * Since: 3.14 222 */ 223 public Device getDevice() 224 { 225 auto p = gtk_gesture_get_device(gtkGesture); 226 227 if(p is null) 228 { 229 return null; 230 } 231 232 return ObjectG.getDObject!(Device)(cast(GdkDevice*) p); 233 } 234 235 /** 236 * Returns all gestures in the group of @gesture 237 * 238 * Returns: The list 239 * of #GtkGestures, free with g_list_free() 240 * 241 * Since: 3.14 242 */ 243 public ListG getGroup() 244 { 245 auto p = gtk_gesture_get_group(gtkGesture); 246 247 if(p is null) 248 { 249 return null; 250 } 251 252 return new ListG(cast(GList*) p); 253 } 254 255 /** 256 * Returns the last event that was processed for @sequence. 257 * 258 * Note that the returned pointer is only valid as long as the @sequence 259 * is still interpreted by the @gesture. If in doubt, you should make 260 * a copy of the event. 261 * 262 * Params: 263 * sequence = a #GdkEventSequence 264 * 265 * Returns: The last event from @sequence 266 */ 267 public Event getLastEvent(GdkEventSequence* sequence) 268 { 269 auto p = gtk_gesture_get_last_event(gtkGesture, sequence); 270 271 if(p is null) 272 { 273 return null; 274 } 275 276 return ObjectG.getDObject!(Event)(cast(GdkEvent*) p); 277 } 278 279 /** 280 * Returns the #GdkEventSequence that was last updated on @gesture. 281 * 282 * Returns: The last updated sequence 283 * 284 * Since: 3.14 285 */ 286 public GdkEventSequence* getLastUpdatedSequence() 287 { 288 return gtk_gesture_get_last_updated_sequence(gtkGesture); 289 } 290 291 /** 292 * If @sequence is currently being interpreted by @gesture, this 293 * function returns %TRUE and fills in @x and @y with the last coordinates 294 * stored for that event sequence. The coordinates are always relative to the 295 * widget allocation. 296 * 297 * Params: 298 * sequence = a #GdkEventSequence, or %NULL for pointer events 299 * x = return location for X axis of the sequence coordinates 300 * y = return location for Y axis of the sequence coordinates 301 * 302 * Returns: %TRUE if @sequence is currently interpreted 303 * 304 * Since: 3.14 305 */ 306 public bool getPoint(GdkEventSequence* sequence, out double x, out double y) 307 { 308 return gtk_gesture_get_point(gtkGesture, sequence, &x, &y) != 0; 309 } 310 311 /** 312 * Returns the @sequence state, as seen by @gesture. 313 * 314 * Params: 315 * sequence = a #GdkEventSequence 316 * 317 * Returns: The sequence state in @gesture 318 * 319 * Since: 3.14 320 */ 321 public GtkEventSequenceState getSequenceState(GdkEventSequence* sequence) 322 { 323 return gtk_gesture_get_sequence_state(gtkGesture, sequence); 324 } 325 326 /** 327 * Returns the list of #GdkEventSequences currently being interpreted 328 * by @gesture. 329 * 330 * Returns: A list 331 * of #GdkEventSequences, the list elements are owned by GTK+ 332 * and must not be freed or modified, the list itself must be deleted 333 * through g_list_free() 334 * 335 * Since: 3.14 336 */ 337 public ListG getSequences() 338 { 339 auto p = gtk_gesture_get_sequences(gtkGesture); 340 341 if(p is null) 342 { 343 return null; 344 } 345 346 return new ListG(cast(GList*) p); 347 } 348 349 /** 350 * Returns the user-defined window that receives the events 351 * handled by @gesture. See gtk_gesture_set_window() for more 352 * information. 353 * 354 * Returns: the user defined window, or %NULL if none 355 * 356 * Since: 3.14 357 */ 358 public Window getWindow() 359 { 360 auto p = gtk_gesture_get_window(gtkGesture); 361 362 if(p is null) 363 { 364 return null; 365 } 366 367 return ObjectG.getDObject!(Window)(cast(GdkWindow*) p); 368 } 369 370 /** 371 * Adds @gesture to the same group than @group_gesture. Gestures 372 * are by default isolated in their own groups. 373 * 374 * When gestures are grouped, the state of #GdkEventSequences 375 * is kept in sync for all of those, so calling gtk_gesture_set_sequence_state(), 376 * on one will transfer the same value to the others. 377 * 378 * Groups also perform an "implicit grabbing" of sequences, if a 379 * #GdkEventSequence state is set to #GTK_EVENT_SEQUENCE_CLAIMED on one group, 380 * every other gesture group attached to the same #GtkWidget will switch the 381 * state for that sequence to #GTK_EVENT_SEQUENCE_DENIED. 382 * 383 * Params: 384 * gesture = a #GtkGesture 385 * 386 * Since: 3.14 387 */ 388 public void group(Gesture gesture) 389 { 390 gtk_gesture_group(gtkGesture, (gesture is null) ? null : gesture.getGestureStruct()); 391 } 392 393 /** 394 * Returns %TRUE if @gesture is currently handling events corresponding to 395 * @sequence. 396 * 397 * Params: 398 * sequence = a #GdkEventSequence or %NULL 399 * 400 * Returns: %TRUE if @gesture is handling @sequence, %FALSE otherwise 401 * 402 * Since: 3.14 403 */ 404 public bool handlesSequence(GdkEventSequence* sequence) 405 { 406 return gtk_gesture_handles_sequence(gtkGesture, sequence) != 0; 407 } 408 409 /** 410 * Returns %TRUE if the gesture is currently active. 411 * A gesture is active meanwhile there are touch sequences 412 * interacting with it. 413 * 414 * Returns: %TRUE if gesture is active 415 * 416 * Since: 3.14 417 */ 418 public bool isActive() 419 { 420 return gtk_gesture_is_active(gtkGesture) != 0; 421 } 422 423 /** 424 * Returns %TRUE if both gestures pertain to the same group. 425 * 426 * Params: 427 * other = another #GtkGesture 428 * 429 * Returns: whether the gestures are grouped 430 * 431 * Since: 3.14 432 */ 433 public bool isGroupedWith(Gesture other) 434 { 435 return gtk_gesture_is_grouped_with(gtkGesture, (other is null) ? null : other.getGestureStruct()) != 0; 436 } 437 438 /** 439 * Returns %TRUE if the gesture is currently recognized. 440 * A gesture is recognized if there are as many interacting 441 * touch sequences as required by @gesture, and #GtkGesture::check 442 * returned %TRUE for the sequences being currently interpreted. 443 * 444 * Returns: %TRUE if gesture is recognized 445 * 446 * Since: 3.14 447 */ 448 public bool isRecognized() 449 { 450 return gtk_gesture_is_recognized(gtkGesture) != 0; 451 } 452 453 /** 454 * Sets the state of @sequence in @gesture. Sequences start 455 * in state #GTK_EVENT_SEQUENCE_NONE, and whenever they change 456 * state, they can never go back to that state. Likewise, 457 * sequences in state #GTK_EVENT_SEQUENCE_DENIED cannot turn 458 * back to a not denied state. With these rules, the lifetime 459 * of an event sequence is constrained to the next four: 460 * 461 * * None 462 * * None → Denied 463 * * None → Claimed 464 * * None → Claimed → Denied 465 * 466 * Note: Due to event handling ordering, it may be unsafe to 467 * set the state on another gesture within a #GtkGesture::begin 468 * signal handler, as the callback might be executed before 469 * the other gesture knows about the sequence. A safe way to 470 * perform this could be: 471 * 472 * |[ 473 * static void 474 * first_gesture_begin_cb (GtkGesture *first_gesture, 475 * GdkEventSequence *sequence, 476 * gpointer user_data) 477 * { 478 * gtk_gesture_set_sequence_state (first_gesture, sequence, GTK_EVENT_SEQUENCE_ACCEPTED); 479 * gtk_gesture_set_sequence_state (second_gesture, sequence, GTK_EVENT_SEQUENCE_DENIED); 480 * } 481 * 482 * static void 483 * second_gesture_begin_cb (GtkGesture *second_gesture, 484 * GdkEventSequence *sequence, 485 * gpointer user_data) 486 * { 487 * if (gtk_gesture_get_sequence_state (first_gesture, sequence) == GTK_EVENT_SEQUENCE_ACCEPTED) 488 * gtk_gesture_set_sequence_state (second_gesture, sequence, GTK_EVENT_SEQUENCE_DENIED); 489 * } 490 * ]| 491 * 492 * If both gestures are in the same group, just set the state on 493 * the gesture emitting the event, the sequence will be already 494 * be initialized to the group's global state when the second 495 * gesture processes the event. 496 * 497 * Params: 498 * sequence = a #GdkEventSequence 499 * state = the sequence state 500 * 501 * Returns: %TRUE if @sequence is handled by @gesture, 502 * and the state is changed successfully 503 * 504 * Since: 3.14 505 */ 506 public bool setSequenceState(GdkEventSequence* sequence, GtkEventSequenceState state) 507 { 508 return gtk_gesture_set_sequence_state(gtkGesture, sequence, state) != 0; 509 } 510 511 /** 512 * Sets the state of all sequences that @gesture is currently 513 * interacting with. See gtk_gesture_set_sequence_state() 514 * for more details on sequence states. 515 * 516 * Params: 517 * state = the sequence state 518 * 519 * Returns: %TRUE if the state of at least one sequence 520 * was changed successfully 521 * 522 * Since: 3.14 523 */ 524 public bool setState(GtkEventSequenceState state) 525 { 526 return gtk_gesture_set_state(gtkGesture, state) != 0; 527 } 528 529 /** 530 * Sets a specific window to receive events about, so @gesture 531 * will effectively handle only events targeting @window, or 532 * a child of it. @window must pertain to gtk_event_controller_get_widget(). 533 * 534 * Params: 535 * window = a #GdkWindow, or %NULL 536 * 537 * Since: 3.14 538 */ 539 public void setWindow(Window window) 540 { 541 gtk_gesture_set_window(gtkGesture, (window is null) ? null : window.getWindowStruct()); 542 } 543 544 /** 545 * Separates @gesture into an isolated group. 546 * 547 * Since: 3.14 548 */ 549 public void ungroup() 550 { 551 gtk_gesture_ungroup(gtkGesture); 552 } 553 554 protected class OnBeginDelegateWrapper 555 { 556 void delegate(GdkEventSequence*, Gesture) dlg; 557 gulong handlerId; 558 559 this(void delegate(GdkEventSequence*, Gesture) dlg) 560 { 561 this.dlg = dlg; 562 onBeginListeners ~= this; 563 } 564 565 void remove(OnBeginDelegateWrapper source) 566 { 567 foreach(index, wrapper; onBeginListeners) 568 { 569 if (wrapper.handlerId == source.handlerId) 570 { 571 onBeginListeners[index] = null; 572 onBeginListeners = std.algorithm.remove(onBeginListeners, index); 573 break; 574 } 575 } 576 } 577 } 578 OnBeginDelegateWrapper[] onBeginListeners; 579 580 /** 581 * This signal is emitted when the gesture is recognized. This means the 582 * number of touch sequences matches #GtkGesture:n-points, and the #GtkGesture::check 583 * handler(s) returned #TRUE. 584 * 585 * Note: These conditions may also happen when an extra touch (eg. a third touch 586 * on a 2-touches gesture) is lifted, in that situation @sequence won't pertain 587 * to the current set of active touches, so don't rely on this being true. 588 * 589 * Params: 590 * sequence = the #GdkEventSequence that made the gesture to be recognized 591 * 592 * Since: 3.14 593 */ 594 gulong addOnBegin(void delegate(GdkEventSequence*, Gesture) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0) 595 { 596 auto wrapper = new OnBeginDelegateWrapper(dlg); 597 wrapper.handlerId = Signals.connectData( 598 this, 599 "begin", 600 cast(GCallback)&callBackBegin, 601 cast(void*)wrapper, 602 cast(GClosureNotify)&callBackBeginDestroy, 603 connectFlags); 604 return wrapper.handlerId; 605 } 606 607 extern(C) static void callBackBegin(GtkGesture* gestureStruct, GdkEventSequence* sequence, OnBeginDelegateWrapper wrapper) 608 { 609 wrapper.dlg(sequence, wrapper.outer); 610 } 611 612 extern(C) static void callBackBeginDestroy(OnBeginDelegateWrapper wrapper, GClosure* closure) 613 { 614 wrapper.remove(wrapper); 615 } 616 617 protected class OnBeginGenericDelegateWrapper 618 { 619 void delegate(Event, Gesture) dlg; 620 gulong handlerId; 621 622 this(void delegate(Event, Gesture) dlg) 623 { 624 this.dlg = dlg; 625 onBeginGenericListeners ~= this; 626 } 627 628 void remove(OnBeginGenericDelegateWrapper source) 629 { 630 foreach(index, wrapper; onBeginGenericListeners) 631 { 632 if (wrapper.handlerId == source.handlerId) 633 { 634 onBeginGenericListeners[index] = null; 635 onBeginGenericListeners = std.algorithm.remove(onBeginGenericListeners, index); 636 break; 637 } 638 } 639 } 640 } 641 OnBeginGenericDelegateWrapper[] onBeginGenericListeners; 642 643 /** 644 * This signal is emitted when the gesture is recognized. This means the 645 * number of touch sequences matches #GtkGesture:n-points, and the #GtkGesture::check 646 * handler(s) returned #TRUE. 647 * 648 * Note: These conditions may also happen when an extra touch (eg. a third touch 649 * on a 2-touches gesture) is lifted, in that situation @sequence won't pertain 650 * to the current set of active touches, so don't rely on this being true. 651 * 652 * Params: 653 * sequence = the #GdkEventSequence that made the gesture to be recognized 654 * 655 * Since: 3.14 656 */ 657 gulong addOnBegin(void delegate(Event, Gesture) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0) 658 { 659 auto wrapper = new OnBeginGenericDelegateWrapper(dlg); 660 wrapper.handlerId = Signals.connectData( 661 this, 662 "begin", 663 cast(GCallback)&callBackBeginGeneric, 664 cast(void*)wrapper, 665 cast(GClosureNotify)&callBackBeginGenericDestroy, 666 connectFlags); 667 return wrapper.handlerId; 668 } 669 670 extern(C) static void callBackBeginGeneric(GtkGesture* gestureStruct, GdkEvent* sequence, OnBeginGenericDelegateWrapper wrapper) 671 { 672 wrapper.dlg(ObjectG.getDObject!(Event)(sequence), wrapper.outer); 673 } 674 675 extern(C) static void callBackBeginGenericDestroy(OnBeginGenericDelegateWrapper wrapper, GClosure* closure) 676 { 677 wrapper.remove(wrapper); 678 } 679 680 protected class OnCancelDelegateWrapper 681 { 682 void delegate(GdkEventSequence*, Gesture) dlg; 683 gulong handlerId; 684 685 this(void delegate(GdkEventSequence*, Gesture) dlg) 686 { 687 this.dlg = dlg; 688 onCancelListeners ~= this; 689 } 690 691 void remove(OnCancelDelegateWrapper source) 692 { 693 foreach(index, wrapper; onCancelListeners) 694 { 695 if (wrapper.handlerId == source.handlerId) 696 { 697 onCancelListeners[index] = null; 698 onCancelListeners = std.algorithm.remove(onCancelListeners, index); 699 break; 700 } 701 } 702 } 703 } 704 OnCancelDelegateWrapper[] onCancelListeners; 705 706 /** 707 * This signal is emitted whenever a sequence is cancelled. This usually 708 * happens on active touches when gtk_event_controller_reset() is called 709 * on @gesture (manually, due to grabs...), or the individual @sequence 710 * was claimed by parent widgets' controllers (see gtk_gesture_set_sequence_state()). 711 * 712 * @gesture must forget everything about @sequence as a reaction to this signal. 713 * 714 * Params: 715 * sequence = the #GdkEventSequence that was cancelled 716 * 717 * Since: 3.14 718 */ 719 gulong addOnCancel(void delegate(GdkEventSequence*, Gesture) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0) 720 { 721 auto wrapper = new OnCancelDelegateWrapper(dlg); 722 wrapper.handlerId = Signals.connectData( 723 this, 724 "cancel", 725 cast(GCallback)&callBackCancel, 726 cast(void*)wrapper, 727 cast(GClosureNotify)&callBackCancelDestroy, 728 connectFlags); 729 return wrapper.handlerId; 730 } 731 732 extern(C) static void callBackCancel(GtkGesture* gestureStruct, GdkEventSequence* sequence, OnCancelDelegateWrapper wrapper) 733 { 734 wrapper.dlg(sequence, wrapper.outer); 735 } 736 737 extern(C) static void callBackCancelDestroy(OnCancelDelegateWrapper wrapper, GClosure* closure) 738 { 739 wrapper.remove(wrapper); 740 } 741 742 protected class OnCancelGenericDelegateWrapper 743 { 744 void delegate(Event, Gesture) dlg; 745 gulong handlerId; 746 747 this(void delegate(Event, Gesture) dlg) 748 { 749 this.dlg = dlg; 750 onCancelGenericListeners ~= this; 751 } 752 753 void remove(OnCancelGenericDelegateWrapper source) 754 { 755 foreach(index, wrapper; onCancelGenericListeners) 756 { 757 if (wrapper.handlerId == source.handlerId) 758 { 759 onCancelGenericListeners[index] = null; 760 onCancelGenericListeners = std.algorithm.remove(onCancelGenericListeners, index); 761 break; 762 } 763 } 764 } 765 } 766 OnCancelGenericDelegateWrapper[] onCancelGenericListeners; 767 768 /** 769 * This signal is emitted whenever a sequence is cancelled. This usually 770 * happens on active touches when gtk_event_controller_reset() is called 771 * on @gesture (manually, due to grabs...), or the individual @sequence 772 * was claimed by parent widgets' controllers (see gtk_gesture_set_sequence_state()). 773 * 774 * @gesture must forget everything about @sequence as a reaction to this signal. 775 * 776 * Params: 777 * sequence = the #GdkEventSequence that was cancelled 778 * 779 * Since: 3.14 780 */ 781 gulong addOnCancel(void delegate(Event, Gesture) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0) 782 { 783 auto wrapper = new OnCancelGenericDelegateWrapper(dlg); 784 wrapper.handlerId = Signals.connectData( 785 this, 786 "cancel", 787 cast(GCallback)&callBackCancelGeneric, 788 cast(void*)wrapper, 789 cast(GClosureNotify)&callBackCancelGenericDestroy, 790 connectFlags); 791 return wrapper.handlerId; 792 } 793 794 extern(C) static void callBackCancelGeneric(GtkGesture* gestureStruct, GdkEvent* sequence, OnCancelGenericDelegateWrapper wrapper) 795 { 796 wrapper.dlg(ObjectG.getDObject!(Event)(sequence), wrapper.outer); 797 } 798 799 extern(C) static void callBackCancelGenericDestroy(OnCancelGenericDelegateWrapper wrapper, GClosure* closure) 800 { 801 wrapper.remove(wrapper); 802 } 803 804 protected class OnEndDelegateWrapper 805 { 806 void delegate(GdkEventSequence*, Gesture) dlg; 807 gulong handlerId; 808 809 this(void delegate(GdkEventSequence*, Gesture) dlg) 810 { 811 this.dlg = dlg; 812 onEndListeners ~= this; 813 } 814 815 void remove(OnEndDelegateWrapper source) 816 { 817 foreach(index, wrapper; onEndListeners) 818 { 819 if (wrapper.handlerId == source.handlerId) 820 { 821 onEndListeners[index] = null; 822 onEndListeners = std.algorithm.remove(onEndListeners, index); 823 break; 824 } 825 } 826 } 827 } 828 OnEndDelegateWrapper[] onEndListeners; 829 830 /** 831 * This signal is emitted when @gesture either stopped recognizing the event 832 * sequences as something to be handled (the #GtkGesture::check handler returned 833 * %FALSE), or the number of touch sequences became higher or lower than 834 * #GtkGesture:n-points. 835 * 836 * Note: @sequence might not pertain to the group of sequences that were 837 * previously triggering recognition on @gesture (ie. a just pressed touch 838 * sequence that exceeds #GtkGesture:n-points). This situation may be detected 839 * by checking through gtk_gesture_handles_sequence(). 840 * 841 * Params: 842 * sequence = the #GdkEventSequence that made gesture recognition to finish 843 * 844 * Since: 3.14 845 */ 846 gulong addOnEnd(void delegate(GdkEventSequence*, Gesture) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0) 847 { 848 auto wrapper = new OnEndDelegateWrapper(dlg); 849 wrapper.handlerId = Signals.connectData( 850 this, 851 "end", 852 cast(GCallback)&callBackEnd, 853 cast(void*)wrapper, 854 cast(GClosureNotify)&callBackEndDestroy, 855 connectFlags); 856 return wrapper.handlerId; 857 } 858 859 extern(C) static void callBackEnd(GtkGesture* gestureStruct, GdkEventSequence* sequence, OnEndDelegateWrapper wrapper) 860 { 861 wrapper.dlg(sequence, wrapper.outer); 862 } 863 864 extern(C) static void callBackEndDestroy(OnEndDelegateWrapper wrapper, GClosure* closure) 865 { 866 wrapper.remove(wrapper); 867 } 868 869 protected class OnEndGenericDelegateWrapper 870 { 871 void delegate(Event, Gesture) dlg; 872 gulong handlerId; 873 874 this(void delegate(Event, Gesture) dlg) 875 { 876 this.dlg = dlg; 877 onEndGenericListeners ~= this; 878 } 879 880 void remove(OnEndGenericDelegateWrapper source) 881 { 882 foreach(index, wrapper; onEndGenericListeners) 883 { 884 if (wrapper.handlerId == source.handlerId) 885 { 886 onEndGenericListeners[index] = null; 887 onEndGenericListeners = std.algorithm.remove(onEndGenericListeners, index); 888 break; 889 } 890 } 891 } 892 } 893 OnEndGenericDelegateWrapper[] onEndGenericListeners; 894 895 /** 896 * This signal is emitted when @gesture either stopped recognizing the event 897 * sequences as something to be handled (the #GtkGesture::check handler returned 898 * %FALSE), or the number of touch sequences became higher or lower than 899 * #GtkGesture:n-points. 900 * 901 * Note: @sequence might not pertain to the group of sequences that were 902 * previously triggering recognition on @gesture (ie. a just pressed touch 903 * sequence that exceeds #GtkGesture:n-points). This situation may be detected 904 * by checking through gtk_gesture_handles_sequence(). 905 * 906 * Params: 907 * sequence = the #GdkEventSequence that made gesture recognition to finish 908 * 909 * Since: 3.14 910 */ 911 gulong addOnEnd(void delegate(Event, Gesture) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0) 912 { 913 auto wrapper = new OnEndGenericDelegateWrapper(dlg); 914 wrapper.handlerId = Signals.connectData( 915 this, 916 "end", 917 cast(GCallback)&callBackEndGeneric, 918 cast(void*)wrapper, 919 cast(GClosureNotify)&callBackEndGenericDestroy, 920 connectFlags); 921 return wrapper.handlerId; 922 } 923 924 extern(C) static void callBackEndGeneric(GtkGesture* gestureStruct, GdkEvent* sequence, OnEndGenericDelegateWrapper wrapper) 925 { 926 wrapper.dlg(ObjectG.getDObject!(Event)(sequence), wrapper.outer); 927 } 928 929 extern(C) static void callBackEndGenericDestroy(OnEndGenericDelegateWrapper wrapper, GClosure* closure) 930 { 931 wrapper.remove(wrapper); 932 } 933 934 protected class OnSequenceStateChangedDelegateWrapper 935 { 936 void delegate(GdkEventSequence*, GtkEventSequenceState, Gesture) dlg; 937 gulong handlerId; 938 939 this(void delegate(GdkEventSequence*, GtkEventSequenceState, Gesture) dlg) 940 { 941 this.dlg = dlg; 942 onSequenceStateChangedListeners ~= this; 943 } 944 945 void remove(OnSequenceStateChangedDelegateWrapper source) 946 { 947 foreach(index, wrapper; onSequenceStateChangedListeners) 948 { 949 if (wrapper.handlerId == source.handlerId) 950 { 951 onSequenceStateChangedListeners[index] = null; 952 onSequenceStateChangedListeners = std.algorithm.remove(onSequenceStateChangedListeners, index); 953 break; 954 } 955 } 956 } 957 } 958 OnSequenceStateChangedDelegateWrapper[] onSequenceStateChangedListeners; 959 960 /** 961 * This signal is emitted whenever a sequence state changes. See 962 * gtk_gesture_set_sequence_state() to know more about the expectable 963 * sequence lifetimes. 964 * 965 * Params: 966 * sequence = the #GdkEventSequence that was cancelled 967 * state = the new sequence state 968 * 969 * Since: 3.14 970 */ 971 gulong addOnSequenceStateChanged(void delegate(GdkEventSequence*, GtkEventSequenceState, Gesture) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0) 972 { 973 auto wrapper = new OnSequenceStateChangedDelegateWrapper(dlg); 974 wrapper.handlerId = Signals.connectData( 975 this, 976 "sequence-state-changed", 977 cast(GCallback)&callBackSequenceStateChanged, 978 cast(void*)wrapper, 979 cast(GClosureNotify)&callBackSequenceStateChangedDestroy, 980 connectFlags); 981 return wrapper.handlerId; 982 } 983 984 extern(C) static void callBackSequenceStateChanged(GtkGesture* gestureStruct, GdkEventSequence* sequence, GtkEventSequenceState state, OnSequenceStateChangedDelegateWrapper wrapper) 985 { 986 wrapper.dlg(sequence, state, wrapper.outer); 987 } 988 989 extern(C) static void callBackSequenceStateChangedDestroy(OnSequenceStateChangedDelegateWrapper wrapper, GClosure* closure) 990 { 991 wrapper.remove(wrapper); 992 } 993 994 protected class OnSequenceStateChangedGenericDelegateWrapper 995 { 996 void delegate(Event, GtkEventSequenceState, Gesture) dlg; 997 gulong handlerId; 998 999 this(void delegate(Event, GtkEventSequenceState, Gesture) dlg) 1000 { 1001 this.dlg = dlg; 1002 onSequenceStateChangedGenericListeners ~= this; 1003 } 1004 1005 void remove(OnSequenceStateChangedGenericDelegateWrapper source) 1006 { 1007 foreach(index, wrapper; onSequenceStateChangedGenericListeners) 1008 { 1009 if (wrapper.handlerId == source.handlerId) 1010 { 1011 onSequenceStateChangedGenericListeners[index] = null; 1012 onSequenceStateChangedGenericListeners = std.algorithm.remove(onSequenceStateChangedGenericListeners, index); 1013 break; 1014 } 1015 } 1016 } 1017 } 1018 OnSequenceStateChangedGenericDelegateWrapper[] onSequenceStateChangedGenericListeners; 1019 1020 /** 1021 * This signal is emitted whenever a sequence state changes. See 1022 * gtk_gesture_set_sequence_state() to know more about the expectable 1023 * sequence lifetimes. 1024 * 1025 * Params: 1026 * sequence = the #GdkEventSequence that was cancelled 1027 * state = the new sequence state 1028 * 1029 * Since: 3.14 1030 */ 1031 gulong addOnSequenceStateChanged(void delegate(Event, GtkEventSequenceState, Gesture) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0) 1032 { 1033 auto wrapper = new OnSequenceStateChangedGenericDelegateWrapper(dlg); 1034 wrapper.handlerId = Signals.connectData( 1035 this, 1036 "sequence-state-changed", 1037 cast(GCallback)&callBackSequenceStateChangedGeneric, 1038 cast(void*)wrapper, 1039 cast(GClosureNotify)&callBackSequenceStateChangedGenericDestroy, 1040 connectFlags); 1041 return wrapper.handlerId; 1042 } 1043 1044 extern(C) static void callBackSequenceStateChangedGeneric(GtkGesture* gestureStruct, GdkEvent* sequence, GtkEventSequenceState state, OnSequenceStateChangedGenericDelegateWrapper wrapper) 1045 { 1046 wrapper.dlg(ObjectG.getDObject!(Event)(sequence), state, wrapper.outer); 1047 } 1048 1049 extern(C) static void callBackSequenceStateChangedGenericDestroy(OnSequenceStateChangedGenericDelegateWrapper wrapper, GClosure* closure) 1050 { 1051 wrapper.remove(wrapper); 1052 } 1053 1054 protected class OnUpdateDelegateWrapper 1055 { 1056 void delegate(GdkEventSequence*, Gesture) dlg; 1057 gulong handlerId; 1058 1059 this(void delegate(GdkEventSequence*, Gesture) dlg) 1060 { 1061 this.dlg = dlg; 1062 onUpdateListeners ~= this; 1063 } 1064 1065 void remove(OnUpdateDelegateWrapper source) 1066 { 1067 foreach(index, wrapper; onUpdateListeners) 1068 { 1069 if (wrapper.handlerId == source.handlerId) 1070 { 1071 onUpdateListeners[index] = null; 1072 onUpdateListeners = std.algorithm.remove(onUpdateListeners, index); 1073 break; 1074 } 1075 } 1076 } 1077 } 1078 OnUpdateDelegateWrapper[] onUpdateListeners; 1079 1080 /** 1081 * This signal is emitted whenever an event is handled while the gesture is 1082 * recognized. @sequence is guaranteed to pertain to the set of active touches. 1083 * 1084 * Params: 1085 * sequence = the #GdkEventSequence that was updated 1086 * 1087 * Since: 3.14 1088 */ 1089 gulong addOnUpdate(void delegate(GdkEventSequence*, Gesture) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0) 1090 { 1091 auto wrapper = new OnUpdateDelegateWrapper(dlg); 1092 wrapper.handlerId = Signals.connectData( 1093 this, 1094 "update", 1095 cast(GCallback)&callBackUpdate, 1096 cast(void*)wrapper, 1097 cast(GClosureNotify)&callBackUpdateDestroy, 1098 connectFlags); 1099 return wrapper.handlerId; 1100 } 1101 1102 extern(C) static void callBackUpdate(GtkGesture* gestureStruct, GdkEventSequence* sequence, OnUpdateDelegateWrapper wrapper) 1103 { 1104 wrapper.dlg(sequence, wrapper.outer); 1105 } 1106 1107 extern(C) static void callBackUpdateDestroy(OnUpdateDelegateWrapper wrapper, GClosure* closure) 1108 { 1109 wrapper.remove(wrapper); 1110 } 1111 1112 protected class OnUpdateGenericDelegateWrapper 1113 { 1114 void delegate(Event, Gesture) dlg; 1115 gulong handlerId; 1116 1117 this(void delegate(Event, Gesture) dlg) 1118 { 1119 this.dlg = dlg; 1120 onUpdateGenericListeners ~= this; 1121 } 1122 1123 void remove(OnUpdateGenericDelegateWrapper source) 1124 { 1125 foreach(index, wrapper; onUpdateGenericListeners) 1126 { 1127 if (wrapper.handlerId == source.handlerId) 1128 { 1129 onUpdateGenericListeners[index] = null; 1130 onUpdateGenericListeners = std.algorithm.remove(onUpdateGenericListeners, index); 1131 break; 1132 } 1133 } 1134 } 1135 } 1136 OnUpdateGenericDelegateWrapper[] onUpdateGenericListeners; 1137 1138 /** 1139 * This signal is emitted whenever an event is handled while the gesture is 1140 * recognized. @sequence is guaranteed to pertain to the set of active touches. 1141 * 1142 * Params: 1143 * sequence = the #GdkEventSequence that was updated 1144 * 1145 * Since: 3.14 1146 */ 1147 gulong addOnUpdate(void delegate(Event, Gesture) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0) 1148 { 1149 auto wrapper = new OnUpdateGenericDelegateWrapper(dlg); 1150 wrapper.handlerId = Signals.connectData( 1151 this, 1152 "update", 1153 cast(GCallback)&callBackUpdateGeneric, 1154 cast(void*)wrapper, 1155 cast(GClosureNotify)&callBackUpdateGenericDestroy, 1156 connectFlags); 1157 return wrapper.handlerId; 1158 } 1159 1160 extern(C) static void callBackUpdateGeneric(GtkGesture* gestureStruct, GdkEvent* sequence, OnUpdateGenericDelegateWrapper wrapper) 1161 { 1162 wrapper.dlg(ObjectG.getDObject!(Event)(sequence), wrapper.outer); 1163 } 1164 1165 extern(C) static void callBackUpdateGenericDestroy(OnUpdateGenericDelegateWrapper wrapper, GClosure* closure) 1166 { 1167 wrapper.remove(wrapper); 1168 } 1169 }