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