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 /** 151 * Sets our main struct and passes it to the parent class. 152 */ 153 public this (GtkGesture* gtkGesture, bool ownedRef = false) 154 { 155 this.gtkGesture = gtkGesture; 156 super(cast(GtkEventController*)gtkGesture, ownedRef); 157 } 158 159 160 /** */ 161 public static GType getType() 162 { 163 return gtk_gesture_get_type(); 164 } 165 166 /** 167 * If there are touch sequences being currently handled by @gesture, 168 * this function returns %TRUE and fills in @rect with the bounding 169 * box containing all active touches. Otherwise, %FALSE will be 170 * returned. 171 * 172 * Note: This function will yield unexpected results on touchpad 173 * gestures. Since there is no correlation between physical and 174 * pixel distances, these will look as if constrained in an 175 * infinitely small area, @rect width and height will thus be 0 176 * regardless of the number of touchpoints. 177 * 178 * Params: 179 * rect = bounding box containing all active touches. 180 * 181 * Returns: %TRUE if there are active touches, %FALSE otherwise 182 * 183 * Since: 3.14 184 */ 185 public bool getBoundingBox(out GdkRectangle rect) 186 { 187 return gtk_gesture_get_bounding_box(gtkGesture, &rect) != 0; 188 } 189 190 /** 191 * If there are touch sequences being currently handled by @gesture, 192 * this function returns %TRUE and fills in @x and @y with the center 193 * of the bounding box containing all active touches. Otherwise, %FALSE 194 * will be returned. 195 * 196 * Params: 197 * x = X coordinate for the bounding box center 198 * y = Y coordinate for the bounding box center 199 * 200 * Returns: %FALSE if no active touches are present, %TRUE otherwise 201 * 202 * Since: 3.14 203 */ 204 public bool getBoundingBoxCenter(out double x, out double y) 205 { 206 return gtk_gesture_get_bounding_box_center(gtkGesture, &x, &y) != 0; 207 } 208 209 /** 210 * Returns the master #GdkDevice that is currently operating 211 * on @gesture, or %NULL if the gesture is not being interacted. 212 * 213 * Returns: a #GdkDevice, or %NULL 214 * 215 * Since: 3.14 216 */ 217 public Device getDevice() 218 { 219 auto p = gtk_gesture_get_device(gtkGesture); 220 221 if(p is null) 222 { 223 return null; 224 } 225 226 return ObjectG.getDObject!(Device)(cast(GdkDevice*) p); 227 } 228 229 /** 230 * Returns all gestures in the group of @gesture 231 * 232 * Returns: The list 233 * of #GtkGestures, free with g_list_free() 234 * 235 * Since: 3.14 236 */ 237 public ListG getGroup() 238 { 239 auto p = gtk_gesture_get_group(gtkGesture); 240 241 if(p is null) 242 { 243 return null; 244 } 245 246 return new ListG(cast(GList*) p); 247 } 248 249 /** 250 * Returns the last event that was processed for @sequence. 251 * 252 * Note that the returned pointer is only valid as long as the @sequence 253 * is still interpreted by the @gesture. If in doubt, you should make 254 * a copy of the event. 255 * 256 * Params: 257 * sequence = a #GdkEventSequence 258 * 259 * Returns: The last event from @sequence 260 */ 261 public Event getLastEvent(GdkEventSequence* sequence) 262 { 263 auto p = gtk_gesture_get_last_event(gtkGesture, sequence); 264 265 if(p is null) 266 { 267 return null; 268 } 269 270 return ObjectG.getDObject!(Event)(cast(GdkEvent*) p); 271 } 272 273 /** 274 * Returns the #GdkEventSequence that was last updated on @gesture. 275 * 276 * Returns: The last updated sequence 277 * 278 * Since: 3.14 279 */ 280 public GdkEventSequence* getLastUpdatedSequence() 281 { 282 return gtk_gesture_get_last_updated_sequence(gtkGesture); 283 } 284 285 /** 286 * If @sequence is currently being interpreted by @gesture, this 287 * function returns %TRUE and fills in @x and @y with the last coordinates 288 * stored for that event sequence. The coordinates are always relative to the 289 * widget allocation. 290 * 291 * Params: 292 * sequence = a #GdkEventSequence, or %NULL for pointer events 293 * x = return location for X axis of the sequence coordinates 294 * y = return location for Y axis of the sequence coordinates 295 * 296 * Returns: %TRUE if @sequence is currently interpreted 297 * 298 * Since: 3.14 299 */ 300 public bool getPoint(GdkEventSequence* sequence, out double x, out double y) 301 { 302 return gtk_gesture_get_point(gtkGesture, sequence, &x, &y) != 0; 303 } 304 305 /** 306 * Returns the @sequence state, as seen by @gesture. 307 * 308 * Params: 309 * sequence = a #GdkEventSequence 310 * 311 * Returns: The sequence state in @gesture 312 * 313 * Since: 3.14 314 */ 315 public GtkEventSequenceState getSequenceState(GdkEventSequence* sequence) 316 { 317 return gtk_gesture_get_sequence_state(gtkGesture, sequence); 318 } 319 320 /** 321 * Returns the list of #GdkEventSequences currently being interpreted 322 * by @gesture. 323 * 324 * Returns: A list 325 * of #GdkEventSequences, the list elements are owned by GTK+ 326 * and must not be freed or modified, the list itself must be deleted 327 * through g_list_free() 328 * 329 * Since: 3.14 330 */ 331 public ListG getSequences() 332 { 333 auto p = gtk_gesture_get_sequences(gtkGesture); 334 335 if(p is null) 336 { 337 return null; 338 } 339 340 return new ListG(cast(GList*) p); 341 } 342 343 /** 344 * Returns the user-defined window that receives the events 345 * handled by @gesture. See gtk_gesture_set_window() for more 346 * information. 347 * 348 * Returns: the user defined window, or %NULL if none 349 * 350 * Since: 3.14 351 */ 352 public Window getWindow() 353 { 354 auto p = gtk_gesture_get_window(gtkGesture); 355 356 if(p is null) 357 { 358 return null; 359 } 360 361 return ObjectG.getDObject!(Window)(cast(GdkWindow*) p); 362 } 363 364 /** 365 * Adds @gesture to the same group than @group_gesture. Gestures 366 * are by default isolated in their own groups. 367 * 368 * When gestures are grouped, the state of #GdkEventSequences 369 * is kept in sync for all of those, so calling gtk_gesture_set_sequence_state(), 370 * on one will transfer the same value to the others. 371 * 372 * Groups also perform an "implicit grabbing" of sequences, if a 373 * #GdkEventSequence state is set to #GTK_EVENT_SEQUENCE_CLAIMED on one group, 374 * every other gesture group attached to the same #GtkWidget will switch the 375 * state for that sequence to #GTK_EVENT_SEQUENCE_DENIED. 376 * 377 * Params: 378 * gesture = a #GtkGesture 379 * 380 * Since: 3.14 381 */ 382 public void group(Gesture gesture) 383 { 384 gtk_gesture_group(gtkGesture, (gesture is null) ? null : gesture.getGestureStruct()); 385 } 386 387 /** 388 * Returns %TRUE if @gesture is currently handling events corresponding to 389 * @sequence. 390 * 391 * Params: 392 * sequence = a #GdkEventSequence or %NULL 393 * 394 * Returns: %TRUE if @gesture is handling @sequence, %FALSE otherwise 395 * 396 * Since: 3.14 397 */ 398 public bool handlesSequence(GdkEventSequence* sequence) 399 { 400 return gtk_gesture_handles_sequence(gtkGesture, sequence) != 0; 401 } 402 403 /** 404 * Returns %TRUE if the gesture is currently active. 405 * A gesture is active meanwhile there are touch sequences 406 * interacting with it. 407 * 408 * Returns: %TRUE if gesture is active 409 * 410 * Since: 3.14 411 */ 412 public bool isActive() 413 { 414 return gtk_gesture_is_active(gtkGesture) != 0; 415 } 416 417 /** 418 * Returns %TRUE if both gestures pertain to the same group. 419 * 420 * Params: 421 * other = another #GtkGesture 422 * 423 * Returns: whether the gestures are grouped 424 * 425 * Since: 3.14 426 */ 427 public bool isGroupedWith(Gesture other) 428 { 429 return gtk_gesture_is_grouped_with(gtkGesture, (other is null) ? null : other.getGestureStruct()) != 0; 430 } 431 432 /** 433 * Returns %TRUE if the gesture is currently recognized. 434 * A gesture is recognized if there are as many interacting 435 * touch sequences as required by @gesture, and #GtkGesture::check 436 * returned %TRUE for the sequences being currently interpreted. 437 * 438 * Returns: %TRUE if gesture is recognized 439 * 440 * Since: 3.14 441 */ 442 public bool isRecognized() 443 { 444 return gtk_gesture_is_recognized(gtkGesture) != 0; 445 } 446 447 /** 448 * Sets the state of @sequence in @gesture. Sequences start 449 * in state #GTK_EVENT_SEQUENCE_NONE, and whenever they change 450 * state, they can never go back to that state. Likewise, 451 * sequences in state #GTK_EVENT_SEQUENCE_DENIED cannot turn 452 * back to a not denied state. With these rules, the lifetime 453 * of an event sequence is constrained to the next four: 454 * 455 * * None 456 * * None → Denied 457 * * None → Claimed 458 * * None → Claimed → Denied 459 * 460 * Note: Due to event handling ordering, it may be unsafe to 461 * set the state on another gesture within a #GtkGesture::begin 462 * signal handler, as the callback might be executed before 463 * the other gesture knows about the sequence. A safe way to 464 * perform this could be: 465 * 466 * |[ 467 * static void 468 * first_gesture_begin_cb (GtkGesture *first_gesture, 469 * GdkEventSequence *sequence, 470 * gpointer user_data) 471 * { 472 * gtk_gesture_set_sequence_state (first_gesture, sequence, GTK_EVENT_SEQUENCE_ACCEPTED); 473 * gtk_gesture_set_sequence_state (second_gesture, sequence, GTK_EVENT_SEQUENCE_DENIED); 474 * } 475 * 476 * static void 477 * second_gesture_begin_cb (GtkGesture *second_gesture, 478 * GdkEventSequence *sequence, 479 * gpointer user_data) 480 * { 481 * if (gtk_gesture_get_sequence_state (first_gesture, sequence) == GTK_EVENT_SEQUENCE_ACCEPTED) 482 * gtk_gesture_set_sequence_state (second_gesture, sequence, GTK_EVENT_SEQUENCE_DENIED); 483 * } 484 * ]| 485 * 486 * If both gestures are in the same group, just set the state on 487 * the gesture emitting the event, the sequence will be already 488 * be initialized to the group's global state when the second 489 * gesture processes the event. 490 * 491 * Params: 492 * sequence = a #GdkEventSequence 493 * state = the sequence state 494 * 495 * Returns: %TRUE if @sequence is handled by @gesture, 496 * and the state is changed successfully 497 * 498 * Since: 3.14 499 */ 500 public bool setSequenceState(GdkEventSequence* sequence, GtkEventSequenceState state) 501 { 502 return gtk_gesture_set_sequence_state(gtkGesture, sequence, state) != 0; 503 } 504 505 /** 506 * Sets the state of all sequences that @gesture is currently 507 * interacting with. See gtk_gesture_set_sequence_state() 508 * for more details on sequence states. 509 * 510 * Params: 511 * state = the sequence state 512 * 513 * Returns: %TRUE if the state of at least one sequence 514 * was changed successfully 515 * 516 * Since: 3.14 517 */ 518 public bool setState(GtkEventSequenceState state) 519 { 520 return gtk_gesture_set_state(gtkGesture, state) != 0; 521 } 522 523 /** 524 * Sets a specific window to receive events about, so @gesture 525 * will effectively handle only events targeting @window, or 526 * a child of it. @window must pertain to gtk_event_controller_get_widget(). 527 * 528 * Params: 529 * window = a #GdkWindow, or %NULL 530 * 531 * Since: 3.14 532 */ 533 public void setWindow(Window window) 534 { 535 gtk_gesture_set_window(gtkGesture, (window is null) ? null : window.getWindowStruct()); 536 } 537 538 /** 539 * Separates @gesture into an isolated group. 540 * 541 * Since: 3.14 542 */ 543 public void ungroup() 544 { 545 gtk_gesture_ungroup(gtkGesture); 546 } 547 548 protected class OnBeginDelegateWrapper 549 { 550 void delegate(GdkEventSequence*, Gesture) dlg; 551 gulong handlerId; 552 553 this(void delegate(GdkEventSequence*, Gesture) dlg) 554 { 555 this.dlg = dlg; 556 onBeginListeners ~= this; 557 } 558 559 void remove(OnBeginDelegateWrapper source) 560 { 561 foreach(index, wrapper; onBeginListeners) 562 { 563 if (wrapper.handlerId == source.handlerId) 564 { 565 onBeginListeners[index] = null; 566 onBeginListeners = std.algorithm.remove(onBeginListeners, index); 567 break; 568 } 569 } 570 } 571 } 572 OnBeginDelegateWrapper[] onBeginListeners; 573 574 /** 575 * This signal is emitted when the gesture is recognized. This means the 576 * number of touch sequences matches #GtkGesture:n-points, and the #GtkGesture::check 577 * handler(s) returned #TRUE. 578 * 579 * Note: These conditions may also happen when an extra touch (eg. a third touch 580 * on a 2-touches gesture) is lifted, in that situation @sequence won't pertain 581 * to the current set of active touches, so don't rely on this being true. 582 * 583 * Params: 584 * sequence = the #GdkEventSequence that made the gesture to be recognized 585 * 586 * Since: 3.14 587 */ 588 gulong addOnBegin(void delegate(GdkEventSequence*, Gesture) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0) 589 { 590 auto wrapper = new OnBeginDelegateWrapper(dlg); 591 wrapper.handlerId = Signals.connectData( 592 this, 593 "begin", 594 cast(GCallback)&callBackBegin, 595 cast(void*)wrapper, 596 cast(GClosureNotify)&callBackBeginDestroy, 597 connectFlags); 598 return wrapper.handlerId; 599 } 600 601 extern(C) static void callBackBegin(GtkGesture* gestureStruct, GdkEventSequence* sequence, OnBeginDelegateWrapper wrapper) 602 { 603 wrapper.dlg(sequence, wrapper.outer); 604 } 605 606 extern(C) static void callBackBeginDestroy(OnBeginDelegateWrapper wrapper, GClosure* closure) 607 { 608 wrapper.remove(wrapper); 609 } 610 611 protected class OnBeginGenericDelegateWrapper 612 { 613 void delegate(Event, Gesture) dlg; 614 gulong handlerId; 615 616 this(void delegate(Event, Gesture) dlg) 617 { 618 this.dlg = dlg; 619 onBeginGenericListeners ~= this; 620 } 621 622 void remove(OnBeginGenericDelegateWrapper source) 623 { 624 foreach(index, wrapper; onBeginGenericListeners) 625 { 626 if (wrapper.handlerId == source.handlerId) 627 { 628 onBeginGenericListeners[index] = null; 629 onBeginGenericListeners = std.algorithm.remove(onBeginGenericListeners, index); 630 break; 631 } 632 } 633 } 634 } 635 OnBeginGenericDelegateWrapper[] onBeginGenericListeners; 636 637 /** 638 * This signal is emitted when the gesture is recognized. This means the 639 * number of touch sequences matches #GtkGesture:n-points, and the #GtkGesture::check 640 * handler(s) returned #TRUE. 641 * 642 * Note: These conditions may also happen when an extra touch (eg. a third touch 643 * on a 2-touches gesture) is lifted, in that situation @sequence won't pertain 644 * to the current set of active touches, so don't rely on this being true. 645 * 646 * Params: 647 * sequence = the #GdkEventSequence that made the gesture to be recognized 648 * 649 * Since: 3.14 650 */ 651 gulong addOnBegin(void delegate(Event, Gesture) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0) 652 { 653 auto wrapper = new OnBeginGenericDelegateWrapper(dlg); 654 wrapper.handlerId = Signals.connectData( 655 this, 656 "begin", 657 cast(GCallback)&callBackBeginGeneric, 658 cast(void*)wrapper, 659 cast(GClosureNotify)&callBackBeginGenericDestroy, 660 connectFlags); 661 return wrapper.handlerId; 662 } 663 664 extern(C) static void callBackBeginGeneric(GtkGesture* gestureStruct, GdkEvent* sequence, OnBeginGenericDelegateWrapper wrapper) 665 { 666 wrapper.dlg(ObjectG.getDObject!(Event)(sequence), wrapper.outer); 667 } 668 669 extern(C) static void callBackBeginGenericDestroy(OnBeginGenericDelegateWrapper wrapper, GClosure* closure) 670 { 671 wrapper.remove(wrapper); 672 } 673 674 protected class OnCancelDelegateWrapper 675 { 676 void delegate(GdkEventSequence*, Gesture) dlg; 677 gulong handlerId; 678 679 this(void delegate(GdkEventSequence*, Gesture) dlg) 680 { 681 this.dlg = dlg; 682 onCancelListeners ~= this; 683 } 684 685 void remove(OnCancelDelegateWrapper source) 686 { 687 foreach(index, wrapper; onCancelListeners) 688 { 689 if (wrapper.handlerId == source.handlerId) 690 { 691 onCancelListeners[index] = null; 692 onCancelListeners = std.algorithm.remove(onCancelListeners, index); 693 break; 694 } 695 } 696 } 697 } 698 OnCancelDelegateWrapper[] onCancelListeners; 699 700 /** 701 * This signal is emitted whenever a sequence is cancelled. This usually 702 * happens on active touches when gtk_event_controller_reset() is called 703 * on @gesture (manually, due to grabs...), or the individual @sequence 704 * was claimed by parent widgets' controllers (see gtk_gesture_set_sequence_state()). 705 * 706 * @gesture must forget everything about @sequence as a reaction to this signal. 707 * 708 * Params: 709 * sequence = the #GdkEventSequence that was cancelled 710 * 711 * Since: 3.14 712 */ 713 gulong addOnCancel(void delegate(GdkEventSequence*, Gesture) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0) 714 { 715 auto wrapper = new OnCancelDelegateWrapper(dlg); 716 wrapper.handlerId = Signals.connectData( 717 this, 718 "cancel", 719 cast(GCallback)&callBackCancel, 720 cast(void*)wrapper, 721 cast(GClosureNotify)&callBackCancelDestroy, 722 connectFlags); 723 return wrapper.handlerId; 724 } 725 726 extern(C) static void callBackCancel(GtkGesture* gestureStruct, GdkEventSequence* sequence, OnCancelDelegateWrapper wrapper) 727 { 728 wrapper.dlg(sequence, wrapper.outer); 729 } 730 731 extern(C) static void callBackCancelDestroy(OnCancelDelegateWrapper wrapper, GClosure* closure) 732 { 733 wrapper.remove(wrapper); 734 } 735 736 protected class OnCancelGenericDelegateWrapper 737 { 738 void delegate(Event, Gesture) dlg; 739 gulong handlerId; 740 741 this(void delegate(Event, Gesture) dlg) 742 { 743 this.dlg = dlg; 744 onCancelGenericListeners ~= this; 745 } 746 747 void remove(OnCancelGenericDelegateWrapper source) 748 { 749 foreach(index, wrapper; onCancelGenericListeners) 750 { 751 if (wrapper.handlerId == source.handlerId) 752 { 753 onCancelGenericListeners[index] = null; 754 onCancelGenericListeners = std.algorithm.remove(onCancelGenericListeners, index); 755 break; 756 } 757 } 758 } 759 } 760 OnCancelGenericDelegateWrapper[] onCancelGenericListeners; 761 762 /** 763 * This signal is emitted whenever a sequence is cancelled. This usually 764 * happens on active touches when gtk_event_controller_reset() is called 765 * on @gesture (manually, due to grabs...), or the individual @sequence 766 * was claimed by parent widgets' controllers (see gtk_gesture_set_sequence_state()). 767 * 768 * @gesture must forget everything about @sequence as a reaction to this signal. 769 * 770 * Params: 771 * sequence = the #GdkEventSequence that was cancelled 772 * 773 * Since: 3.14 774 */ 775 gulong addOnCancel(void delegate(Event, Gesture) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0) 776 { 777 auto wrapper = new OnCancelGenericDelegateWrapper(dlg); 778 wrapper.handlerId = Signals.connectData( 779 this, 780 "cancel", 781 cast(GCallback)&callBackCancelGeneric, 782 cast(void*)wrapper, 783 cast(GClosureNotify)&callBackCancelGenericDestroy, 784 connectFlags); 785 return wrapper.handlerId; 786 } 787 788 extern(C) static void callBackCancelGeneric(GtkGesture* gestureStruct, GdkEvent* sequence, OnCancelGenericDelegateWrapper wrapper) 789 { 790 wrapper.dlg(ObjectG.getDObject!(Event)(sequence), wrapper.outer); 791 } 792 793 extern(C) static void callBackCancelGenericDestroy(OnCancelGenericDelegateWrapper wrapper, GClosure* closure) 794 { 795 wrapper.remove(wrapper); 796 } 797 798 protected class OnEndDelegateWrapper 799 { 800 void delegate(GdkEventSequence*, Gesture) dlg; 801 gulong handlerId; 802 803 this(void delegate(GdkEventSequence*, Gesture) dlg) 804 { 805 this.dlg = dlg; 806 onEndListeners ~= this; 807 } 808 809 void remove(OnEndDelegateWrapper source) 810 { 811 foreach(index, wrapper; onEndListeners) 812 { 813 if (wrapper.handlerId == source.handlerId) 814 { 815 onEndListeners[index] = null; 816 onEndListeners = std.algorithm.remove(onEndListeners, index); 817 break; 818 } 819 } 820 } 821 } 822 OnEndDelegateWrapper[] onEndListeners; 823 824 /** 825 * This signal is emitted when @gesture either stopped recognizing the event 826 * sequences as something to be handled (the #GtkGesture::check handler returned 827 * %FALSE), or the number of touch sequences became higher or lower than 828 * #GtkGesture:n-points. 829 * 830 * Note: @sequence might not pertain to the group of sequences that were 831 * previously triggering recognition on @gesture (ie. a just pressed touch 832 * sequence that exceeds #GtkGesture:n-points). This situation may be detected 833 * by checking through gtk_gesture_handles_sequence(). 834 * 835 * Params: 836 * sequence = the #GdkEventSequence that made gesture recognition to finish 837 * 838 * Since: 3.14 839 */ 840 gulong addOnEnd(void delegate(GdkEventSequence*, Gesture) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0) 841 { 842 auto wrapper = new OnEndDelegateWrapper(dlg); 843 wrapper.handlerId = Signals.connectData( 844 this, 845 "end", 846 cast(GCallback)&callBackEnd, 847 cast(void*)wrapper, 848 cast(GClosureNotify)&callBackEndDestroy, 849 connectFlags); 850 return wrapper.handlerId; 851 } 852 853 extern(C) static void callBackEnd(GtkGesture* gestureStruct, GdkEventSequence* sequence, OnEndDelegateWrapper wrapper) 854 { 855 wrapper.dlg(sequence, wrapper.outer); 856 } 857 858 extern(C) static void callBackEndDestroy(OnEndDelegateWrapper wrapper, GClosure* closure) 859 { 860 wrapper.remove(wrapper); 861 } 862 863 protected class OnEndGenericDelegateWrapper 864 { 865 void delegate(Event, Gesture) dlg; 866 gulong handlerId; 867 868 this(void delegate(Event, Gesture) dlg) 869 { 870 this.dlg = dlg; 871 onEndGenericListeners ~= this; 872 } 873 874 void remove(OnEndGenericDelegateWrapper source) 875 { 876 foreach(index, wrapper; onEndGenericListeners) 877 { 878 if (wrapper.handlerId == source.handlerId) 879 { 880 onEndGenericListeners[index] = null; 881 onEndGenericListeners = std.algorithm.remove(onEndGenericListeners, index); 882 break; 883 } 884 } 885 } 886 } 887 OnEndGenericDelegateWrapper[] onEndGenericListeners; 888 889 /** 890 * This signal is emitted when @gesture either stopped recognizing the event 891 * sequences as something to be handled (the #GtkGesture::check handler returned 892 * %FALSE), or the number of touch sequences became higher or lower than 893 * #GtkGesture:n-points. 894 * 895 * Note: @sequence might not pertain to the group of sequences that were 896 * previously triggering recognition on @gesture (ie. a just pressed touch 897 * sequence that exceeds #GtkGesture:n-points). This situation may be detected 898 * by checking through gtk_gesture_handles_sequence(). 899 * 900 * Params: 901 * sequence = the #GdkEventSequence that made gesture recognition to finish 902 * 903 * Since: 3.14 904 */ 905 gulong addOnEnd(void delegate(Event, Gesture) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0) 906 { 907 auto wrapper = new OnEndGenericDelegateWrapper(dlg); 908 wrapper.handlerId = Signals.connectData( 909 this, 910 "end", 911 cast(GCallback)&callBackEndGeneric, 912 cast(void*)wrapper, 913 cast(GClosureNotify)&callBackEndGenericDestroy, 914 connectFlags); 915 return wrapper.handlerId; 916 } 917 918 extern(C) static void callBackEndGeneric(GtkGesture* gestureStruct, GdkEvent* sequence, OnEndGenericDelegateWrapper wrapper) 919 { 920 wrapper.dlg(ObjectG.getDObject!(Event)(sequence), wrapper.outer); 921 } 922 923 extern(C) static void callBackEndGenericDestroy(OnEndGenericDelegateWrapper wrapper, GClosure* closure) 924 { 925 wrapper.remove(wrapper); 926 } 927 928 protected class OnSequenceStateChangedDelegateWrapper 929 { 930 void delegate(GdkEventSequence*, GtkEventSequenceState, Gesture) dlg; 931 gulong handlerId; 932 933 this(void delegate(GdkEventSequence*, GtkEventSequenceState, Gesture) dlg) 934 { 935 this.dlg = dlg; 936 onSequenceStateChangedListeners ~= this; 937 } 938 939 void remove(OnSequenceStateChangedDelegateWrapper source) 940 { 941 foreach(index, wrapper; onSequenceStateChangedListeners) 942 { 943 if (wrapper.handlerId == source.handlerId) 944 { 945 onSequenceStateChangedListeners[index] = null; 946 onSequenceStateChangedListeners = std.algorithm.remove(onSequenceStateChangedListeners, index); 947 break; 948 } 949 } 950 } 951 } 952 OnSequenceStateChangedDelegateWrapper[] onSequenceStateChangedListeners; 953 954 /** 955 * This signal is emitted whenever a sequence state changes. See 956 * gtk_gesture_set_sequence_state() to know more about the expectable 957 * sequence lifetimes. 958 * 959 * Params: 960 * sequence = the #GdkEventSequence that was cancelled 961 * state = the new sequence state 962 * 963 * Since: 3.14 964 */ 965 gulong addOnSequenceStateChanged(void delegate(GdkEventSequence*, GtkEventSequenceState, Gesture) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0) 966 { 967 auto wrapper = new OnSequenceStateChangedDelegateWrapper(dlg); 968 wrapper.handlerId = Signals.connectData( 969 this, 970 "sequence-state-changed", 971 cast(GCallback)&callBackSequenceStateChanged, 972 cast(void*)wrapper, 973 cast(GClosureNotify)&callBackSequenceStateChangedDestroy, 974 connectFlags); 975 return wrapper.handlerId; 976 } 977 978 extern(C) static void callBackSequenceStateChanged(GtkGesture* gestureStruct, GdkEventSequence* sequence, GtkEventSequenceState state, OnSequenceStateChangedDelegateWrapper wrapper) 979 { 980 wrapper.dlg(sequence, state, wrapper.outer); 981 } 982 983 extern(C) static void callBackSequenceStateChangedDestroy(OnSequenceStateChangedDelegateWrapper wrapper, GClosure* closure) 984 { 985 wrapper.remove(wrapper); 986 } 987 988 protected class OnSequenceStateChangedGenericDelegateWrapper 989 { 990 void delegate(Event, GtkEventSequenceState, Gesture) dlg; 991 gulong handlerId; 992 993 this(void delegate(Event, GtkEventSequenceState, Gesture) dlg) 994 { 995 this.dlg = dlg; 996 onSequenceStateChangedGenericListeners ~= this; 997 } 998 999 void remove(OnSequenceStateChangedGenericDelegateWrapper source) 1000 { 1001 foreach(index, wrapper; onSequenceStateChangedGenericListeners) 1002 { 1003 if (wrapper.handlerId == source.handlerId) 1004 { 1005 onSequenceStateChangedGenericListeners[index] = null; 1006 onSequenceStateChangedGenericListeners = std.algorithm.remove(onSequenceStateChangedGenericListeners, index); 1007 break; 1008 } 1009 } 1010 } 1011 } 1012 OnSequenceStateChangedGenericDelegateWrapper[] onSequenceStateChangedGenericListeners; 1013 1014 /** 1015 * This signal is emitted whenever a sequence state changes. See 1016 * gtk_gesture_set_sequence_state() to know more about the expectable 1017 * sequence lifetimes. 1018 * 1019 * Params: 1020 * sequence = the #GdkEventSequence that was cancelled 1021 * state = the new sequence state 1022 * 1023 * Since: 3.14 1024 */ 1025 gulong addOnSequenceStateChanged(void delegate(Event, GtkEventSequenceState, Gesture) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0) 1026 { 1027 auto wrapper = new OnSequenceStateChangedGenericDelegateWrapper(dlg); 1028 wrapper.handlerId = Signals.connectData( 1029 this, 1030 "sequence-state-changed", 1031 cast(GCallback)&callBackSequenceStateChangedGeneric, 1032 cast(void*)wrapper, 1033 cast(GClosureNotify)&callBackSequenceStateChangedGenericDestroy, 1034 connectFlags); 1035 return wrapper.handlerId; 1036 } 1037 1038 extern(C) static void callBackSequenceStateChangedGeneric(GtkGesture* gestureStruct, GdkEvent* sequence, GtkEventSequenceState state, OnSequenceStateChangedGenericDelegateWrapper wrapper) 1039 { 1040 wrapper.dlg(ObjectG.getDObject!(Event)(sequence), state, wrapper.outer); 1041 } 1042 1043 extern(C) static void callBackSequenceStateChangedGenericDestroy(OnSequenceStateChangedGenericDelegateWrapper wrapper, GClosure* closure) 1044 { 1045 wrapper.remove(wrapper); 1046 } 1047 1048 protected class OnUpdateDelegateWrapper 1049 { 1050 void delegate(GdkEventSequence*, Gesture) dlg; 1051 gulong handlerId; 1052 1053 this(void delegate(GdkEventSequence*, Gesture) dlg) 1054 { 1055 this.dlg = dlg; 1056 onUpdateListeners ~= this; 1057 } 1058 1059 void remove(OnUpdateDelegateWrapper source) 1060 { 1061 foreach(index, wrapper; onUpdateListeners) 1062 { 1063 if (wrapper.handlerId == source.handlerId) 1064 { 1065 onUpdateListeners[index] = null; 1066 onUpdateListeners = std.algorithm.remove(onUpdateListeners, index); 1067 break; 1068 } 1069 } 1070 } 1071 } 1072 OnUpdateDelegateWrapper[] onUpdateListeners; 1073 1074 /** 1075 * This signal is emitted whenever an event is handled while the gesture is 1076 * recognized. @sequence is guaranteed to pertain to the set of active touches. 1077 * 1078 * Params: 1079 * sequence = the #GdkEventSequence that was updated 1080 * 1081 * Since: 3.14 1082 */ 1083 gulong addOnUpdate(void delegate(GdkEventSequence*, Gesture) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0) 1084 { 1085 auto wrapper = new OnUpdateDelegateWrapper(dlg); 1086 wrapper.handlerId = Signals.connectData( 1087 this, 1088 "update", 1089 cast(GCallback)&callBackUpdate, 1090 cast(void*)wrapper, 1091 cast(GClosureNotify)&callBackUpdateDestroy, 1092 connectFlags); 1093 return wrapper.handlerId; 1094 } 1095 1096 extern(C) static void callBackUpdate(GtkGesture* gestureStruct, GdkEventSequence* sequence, OnUpdateDelegateWrapper wrapper) 1097 { 1098 wrapper.dlg(sequence, wrapper.outer); 1099 } 1100 1101 extern(C) static void callBackUpdateDestroy(OnUpdateDelegateWrapper wrapper, GClosure* closure) 1102 { 1103 wrapper.remove(wrapper); 1104 } 1105 1106 protected class OnUpdateGenericDelegateWrapper 1107 { 1108 void delegate(Event, Gesture) dlg; 1109 gulong handlerId; 1110 1111 this(void delegate(Event, Gesture) dlg) 1112 { 1113 this.dlg = dlg; 1114 onUpdateGenericListeners ~= this; 1115 } 1116 1117 void remove(OnUpdateGenericDelegateWrapper source) 1118 { 1119 foreach(index, wrapper; onUpdateGenericListeners) 1120 { 1121 if (wrapper.handlerId == source.handlerId) 1122 { 1123 onUpdateGenericListeners[index] = null; 1124 onUpdateGenericListeners = std.algorithm.remove(onUpdateGenericListeners, index); 1125 break; 1126 } 1127 } 1128 } 1129 } 1130 OnUpdateGenericDelegateWrapper[] onUpdateGenericListeners; 1131 1132 /** 1133 * This signal is emitted whenever an event is handled while the gesture is 1134 * recognized. @sequence is guaranteed to pertain to the set of active touches. 1135 * 1136 * Params: 1137 * sequence = the #GdkEventSequence that was updated 1138 * 1139 * Since: 3.14 1140 */ 1141 gulong addOnUpdate(void delegate(Event, Gesture) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0) 1142 { 1143 auto wrapper = new OnUpdateGenericDelegateWrapper(dlg); 1144 wrapper.handlerId = Signals.connectData( 1145 this, 1146 "update", 1147 cast(GCallback)&callBackUpdateGeneric, 1148 cast(void*)wrapper, 1149 cast(GClosureNotify)&callBackUpdateGenericDestroy, 1150 connectFlags); 1151 return wrapper.handlerId; 1152 } 1153 1154 extern(C) static void callBackUpdateGeneric(GtkGesture* gestureStruct, GdkEvent* sequence, OnUpdateGenericDelegateWrapper wrapper) 1155 { 1156 wrapper.dlg(ObjectG.getDObject!(Event)(sequence), wrapper.outer); 1157 } 1158 1159 extern(C) static void callBackUpdateGenericDestroy(OnUpdateGenericDelegateWrapper wrapper, GClosure* closure) 1160 { 1161 wrapper.remove(wrapper); 1162 } 1163 }