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