gdkevents.c 23.6 KB
Newer Older
1 2 3 4
/* GDK - The GIMP Drawing Kit
 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
 *
 * This library is free software; you can redistribute it and/or
5
 * modify it under the terms of the GNU Lesser General Public
6 7 8 9 10 11
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
12
 * Lesser General Public License for more details.
13
 *
14
 * You should have received a copy of the GNU Lesser General Public
15 16 17 18 19
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

20
/*
21
 * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
22 23 24 25 26
 * file for a list of people on the GTK+ Team.  See the ChangeLog
 * files for a list of changes.  These files are distributed with
 * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
 */

27
#include "gdk.h"
28
#include "gdkinternals.h"
29

30
typedef struct _GdkIOClosure GdkIOClosure;
31
typedef struct _GdkEventPrivate GdkEventPrivate;
32

33 34
typedef enum
{
35 36 37 38 39 40
  /* Following flag is set for events on the event queue during
   * translation and cleared afterwards.
   */
  GDK_EVENT_PENDING = 1 << 0
} GdkEventFlags;

41 42
struct _GdkIOClosure
{
43 44 45 46 47 48
  GdkInputFunction function;
  GdkInputCondition condition;
  GdkDestroyNotify notify;
  gpointer data;
};

49 50
struct _GdkEventPrivate
{
51 52 53 54
  GdkEvent event;
  guint    flags;
};

55 56 57
/* Private variable declarations
 */

58 59 60 61 62 63 64
static guint32 button_click_time[2] = { 0, 0}; /* The last 2 button click times. Used
						* to determine if the latest button click
						* is part of a double or triple click.
						*/
static GdkWindow *button_window[2] = { NULL, NULL}; /* The last 2 windows to receive button presses.
						     *	Also used to determine if the latest button
						     *	click is part of a double or triple click.
65
					     */
66
static guint button_number[2] = { -1, -1 }; /* The last 2 buttons to be pressed.
67
					     */
68 69 70
GdkEventFunc   _gdk_event_func = NULL;    /* Callback for events */
gpointer       _gdk_event_data = NULL;
GDestroyNotify _gdk_event_notify = NULL;
71

72 73 74 75 76
static guint double_click_time = 250;
#define TRIPLE_CLICK_TIME      (2*double_click_time)
#define DOUBLE_CLICK_DIST      5
#define TRIPLE_CLICK_DIST      5

77 78 79 80 81
/*********************************************
 * Functions for maintaining the event queue *
 *********************************************/

/*************************************************************
82
 * _gdk_event_queue_find_first:
83 84 85 86 87 88 89 90
 *     Find the first event on the queue that is not still
 *     being filled in.
 *   arguments:
 *     
 *   results:
 *     Pointer to the list node for that event, or NULL
 *************************************************************/

91
GList*
92
_gdk_event_queue_find_first (void)
93
{
94
  GList *tmp_list = _gdk_queued_events;
95 96 97

  while (tmp_list)
    {
98
      GdkEventPrivate *event = tmp_list->data;
99 100
      if (!(event->flags & GDK_EVENT_PENDING))
	return tmp_list;
101 102

      tmp_list = g_list_next (tmp_list);
103 104 105 106 107 108
    }

  return NULL;
}

/*************************************************************
109
 * _gdk_event_queue_remove_link:
110 111 112 113 114 115
 *     Remove a specified list node from the event queue.
 *   arguments:
 *     node: Node to remove.
 *   results:
 *************************************************************/

116
void
117
_gdk_event_queue_remove_link (GList *node)
118 119 120 121
{
  if (node->prev)
    node->prev->next = node->next;
  else
122
    _gdk_queued_events = node->next;
123 124 125 126
  
  if (node->next)
    node->next->prev = node->prev;
  else
127
    _gdk_queued_tail = node->prev;
128 129 130
}

/*************************************************************
131
 * _gdk_event_queue_append:
132 133 134 135 136 137
 *     Append an event onto the tail of the event queue.
 *   arguments:
 *     event: Event to append.
 *   results:
 *************************************************************/

138
void
139
_gdk_event_queue_append (GdkEvent *event)
140
{
141
  _gdk_queued_tail = g_list_append (_gdk_queued_tail, event);
142
  
143 144
  if (!_gdk_queued_events)
    _gdk_queued_events = _gdk_queued_tail;
145
  else
146
    _gdk_queued_tail = _gdk_queued_tail->next;
147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164
}

/*************************************************************
 * gdk_event_handler_set:
 *     
 *   arguments:
 *     func: Callback function to be called for each event.
 *     data: Data supplied to the function
 *     notify: function called when function is no longer needed
 * 
 *   results:
 *************************************************************/

void 
gdk_event_handler_set (GdkEventFunc   func,
		       gpointer       data,
		       GDestroyNotify notify)
{
165 166
  if (_gdk_event_notify)
    (*_gdk_event_notify) (_gdk_event_data);
167

168 169 170
  _gdk_event_func = func;
  _gdk_event_data = data;
  _gdk_event_notify = notify;
171 172 173 174 175 176 177 178 179 180 181
}

/*
 *--------------------------------------------------------------
 * gdk_event_get
 *
 *   Gets the next event.
 *
 * Arguments:
 *
 * Results:
182
 *   If an event is waiting that we care about, returns 
183
 *   a pointer to that event, to be freed with gdk_event_free.
184
 *   Otherwise, returns NULL.
185 186 187 188 189 190
 *
 * Side effects:
 *
 *--------------------------------------------------------------
 */

191
GdkEvent*
192 193
gdk_event_get (void)
{
194
  _gdk_events_queue ();
195

196
  return _gdk_event_unqueue ();
197 198
}

199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217
/*
 *--------------------------------------------------------------
 * gdk_event_peek
 *
 *   Gets the next event.
 *
 * Arguments:
 *
 * Results:
 *   If an event is waiting that we care about, returns 
 *   a copy of that event, but does not remove it from
 *   the queue. The pointer is to be freed with gdk_event_free.
 *   Otherwise, returns NULL.
 *
 * Side effects:
 *
 *--------------------------------------------------------------
 */

218
GdkEvent*
219 220 221 222
gdk_event_peek (void)
{
  GList *tmp_list;

223
  tmp_list = _gdk_event_queue_find_first ();
224 225 226 227 228 229 230
  
  if (tmp_list)
    return gdk_event_copy (tmp_list->data);
  else
    return NULL;
}

231 232 233 234 235 236 237 238
void
gdk_event_put (GdkEvent *event)
{
  GdkEvent *new_event;
  
  g_return_if_fail (event != NULL);
  
  new_event = gdk_event_copy (event);
239

240
  _gdk_event_queue_append (new_event);
241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260
}

/*
 *--------------------------------------------------------------
 * gdk_event_copy
 *
 *   Copy a event structure into new storage.
 *
 * Arguments:
 *   "event" is the event struct to copy.
 *
 * Results:
 *   A new event structure.  Free it with gdk_event_free.
 *
 * Side effects:
 *   The reference count of the window in the event is increased.
 *
 *--------------------------------------------------------------
 */

261
static GMemChunk *event_chunk = NULL;
262

263
GdkEvent*
264
_gdk_event_new (void)
265
{
266
  GdkEventPrivate *new_event;
267 268 269
  
  if (event_chunk == NULL)
    event_chunk = g_mem_chunk_new ("events",
270
				   sizeof (GdkEventPrivate),
271 272 273
				   4096,
				   G_ALLOC_AND_FREE);
  
274 275
  new_event = g_chunk_new (GdkEventPrivate, event_chunk);
  new_event->flags = 0;
276
  
277
  return (GdkEvent*) new_event;
278 279 280 281 282 283 284 285 286
}

GdkEvent*
gdk_event_copy (GdkEvent *event)
{
  GdkEvent *new_event;
  
  g_return_val_if_fail (event != NULL, NULL);
  
287
  new_event = _gdk_event_new ();
288 289
  
  *new_event = *event;
290 291
  if (new_event->any.window)
    gdk_window_ref (new_event->any.window);
292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314
  
  switch (event->any.type)
    {
    case GDK_KEY_PRESS:
    case GDK_KEY_RELEASE:
      new_event->key.string = g_strdup (event->key.string);
      break;
      
    case GDK_ENTER_NOTIFY:
    case GDK_LEAVE_NOTIFY:
      if (event->crossing.subwindow != NULL)
	gdk_window_ref (event->crossing.subwindow);
      break;
      
    case GDK_DRAG_ENTER:
    case GDK_DRAG_LEAVE:
    case GDK_DRAG_MOTION:
    case GDK_DRAG_STATUS:
    case GDK_DROP_START:
    case GDK_DROP_FINISHED:
      gdk_drag_context_ref (event->dnd.context);
      break;
      
315 316 317 318
    case GDK_EXPOSE:
      if (event->expose.region)
	new_event->expose.region = gdk_region_copy (event->expose.region);
      break;
319 320 321 322 323 324
      
    case GDK_SETTING:
      new_event->setting.name = g_strdup (new_event->setting.name);
      break;
      
    default:
325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352
      break;
    }
  
  return new_event;
}

/*
 *--------------------------------------------------------------
 * gdk_event_free
 *
 *   Free a event structure obtained from gdk_event_copy.  Do not use
 *   with other event structures.
 *
 * Arguments:
 *   "event" is the event struct to free.
 *
 * Results:
 *
 * Side effects:
 *   The reference count of the window in the event is decreased and
 *   might be freed, too.
 *
 *-------------------------------------------------------------- */

void
gdk_event_free (GdkEvent *event)
{
  g_return_if_fail (event != NULL);
353 354

  g_assert (event_chunk != NULL); /* paranoid */
355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379
  
  if (event->any.window)
    gdk_window_unref (event->any.window);
  
  switch (event->any.type)
    {
    case GDK_KEY_PRESS:
    case GDK_KEY_RELEASE:
      g_free (event->key.string);
      break;
      
    case GDK_ENTER_NOTIFY:
    case GDK_LEAVE_NOTIFY:
      if (event->crossing.subwindow != NULL)
	gdk_window_unref (event->crossing.subwindow);
      break;
      
    case GDK_DRAG_ENTER:
    case GDK_DRAG_LEAVE:
    case GDK_DRAG_MOTION:
    case GDK_DRAG_STATUS:
    case GDK_DROP_START:
    case GDK_DROP_FINISHED:
      gdk_drag_context_unref (event->dnd.context);
      break;
380 381 382 383 384 385

    case GDK_BUTTON_PRESS:
    case GDK_BUTTON_RELEASE:
      if (event->button.axes)
	g_free (event->button.axes);
      break;
386 387 388 389 390 391
      
    case GDK_EXPOSE:
      if (event->expose.region)
	gdk_region_destroy (event->expose.region);
      break;
      
392 393 394 395
    case GDK_MOTION_NOTIFY:
      if (event->motion.axes)
	g_free (event->motion.axes);
      break;
396
      
397 398 399 400
    case GDK_SETTING:
      g_free (event->setting.name);
      break;
      
401 402 403 404 405 406 407
    default:
      break;
    }
  
  g_mem_chunk_free (event_chunk, event);
}

408
/**
409
 * gdk_event_get_time:
410 411 412 413 414 415 416
 * @event: a #GdkEvent
 * 
 * Returns the time stamp from @event, if there is one; otherwise
 * returns #GDK_CURRENT_TIME. If @event is %NULL, returns #GDK_CURRENT_TIME.
 * 
 * Return value: time stamp field from @event
 **/
417 418 419 420 421 422 423 424 425 426 427 428 429
guint32
gdk_event_get_time (GdkEvent *event)
{
  if (event)
    switch (event->type)
      {
      case GDK_MOTION_NOTIFY:
	return event->motion.time;
      case GDK_BUTTON_PRESS:
      case GDK_2BUTTON_PRESS:
      case GDK_3BUTTON_PRESS:
      case GDK_BUTTON_RELEASE:
	return event->button.time;
430 431
      case GDK_SCROLL:
        return event->scroll.time;
432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453
      case GDK_KEY_PRESS:
      case GDK_KEY_RELEASE:
	return event->key.time;
      case GDK_ENTER_NOTIFY:
      case GDK_LEAVE_NOTIFY:
	return event->crossing.time;
      case GDK_PROPERTY_NOTIFY:
	return event->property.time;
      case GDK_SELECTION_CLEAR:
      case GDK_SELECTION_REQUEST:
      case GDK_SELECTION_NOTIFY:
	return event->selection.time;
      case GDK_PROXIMITY_IN:
      case GDK_PROXIMITY_OUT:
	return event->proximity.time;
      case GDK_DRAG_ENTER:
      case GDK_DRAG_LEAVE:
      case GDK_DRAG_MOTION:
      case GDK_DRAG_STATUS:
      case GDK_DROP_START:
      case GDK_DROP_FINISHED:
	return event->dnd.time;
454 455 456 457 458 459 460 461 462 463 464
      case GDK_CLIENT_EVENT:
      case GDK_VISIBILITY_NOTIFY:
      case GDK_NO_EXPOSE:
      case GDK_CONFIGURE:
      case GDK_FOCUS_CHANGE:
      case GDK_NOTHING:
      case GDK_DELETE:
      case GDK_DESTROY:
      case GDK_EXPOSE:
      case GDK_MAP:
      case GDK_UNMAP:
Havoc Pennington's avatar
Havoc Pennington committed
465
      case GDK_WINDOW_STATE:
466
      case GDK_SETTING:
467 468
        /* return current time */
        break;
469 470 471 472 473
      }
  
  return GDK_CURRENT_TIME;
}

474 475 476 477 478 479 480
/**
 * gdk_event_get_state:
 * @event: a #GdkEvent or NULL
 * @state: return location for state
 * 
 * If the event contains a "state" field, puts that field in @state. Otherwise
 * stores an empty state (0). Returns %TRUE if there was a state field
481 482
 * in the event. @event may be %NULL, in which case it's treated
 * as if the event had no state field.
483 484 485 486 487 488 489
 * 
 * Return value: %TRUE if there was a state field in the event 
 **/
gboolean
gdk_event_get_state (GdkEvent        *event,
                     GdkModifierType *state)
{
490 491
  g_return_val_if_fail (state != NULL, FALSE);
  
492 493 494 495
  if (event)
    switch (event->type)
      {
      case GDK_MOTION_NOTIFY:
496 497
	*state = event->motion.state;
        return TRUE;
498 499 500 501
      case GDK_BUTTON_PRESS:
      case GDK_2BUTTON_PRESS:
      case GDK_3BUTTON_PRESS:
      case GDK_BUTTON_RELEASE:
502 503
        *state =  event->button.state;
        return TRUE;
504
      case GDK_SCROLL:
505 506
	*state =  event->scroll.state;
        return TRUE;
507 508
      case GDK_KEY_PRESS:
      case GDK_KEY_RELEASE:
509 510
	*state =  event->key.state;
        return TRUE;
511 512
      case GDK_ENTER_NOTIFY:
      case GDK_LEAVE_NOTIFY:
513 514
	*state =  event->crossing.state;
        return TRUE;
515
      case GDK_PROPERTY_NOTIFY:
516 517
	*state =  event->property.state;
        return TRUE;
518
      case GDK_VISIBILITY_NOTIFY:
519 520
        *state =  event->visibility.state;
        return TRUE;
521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541
      case GDK_CLIENT_EVENT:
      case GDK_NO_EXPOSE:
      case GDK_CONFIGURE:
      case GDK_FOCUS_CHANGE:
      case GDK_SELECTION_CLEAR:
      case GDK_SELECTION_REQUEST:
      case GDK_SELECTION_NOTIFY:
      case GDK_PROXIMITY_IN:
      case GDK_PROXIMITY_OUT:
      case GDK_DRAG_ENTER:
      case GDK_DRAG_LEAVE:
      case GDK_DRAG_MOTION:
      case GDK_DRAG_STATUS:
      case GDK_DROP_START:
      case GDK_DROP_FINISHED:
      case GDK_NOTHING:
      case GDK_DELETE:
      case GDK_DESTROY:
      case GDK_EXPOSE:
      case GDK_MAP:
      case GDK_UNMAP:
Havoc Pennington's avatar
Havoc Pennington committed
542
      case GDK_WINDOW_STATE:
543
      case GDK_SETTING:
544 545 546 547
        /* no state field */
        break;
      }

548 549
  *state = 0;
  return FALSE;
550 551
}

552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670
/**
 * gdk_event_get_coords:
 * @event: a #GdkEvent
 * @x_root: location to put event window x coordinate
 * @y_root: location to put event window y coordinate
 * 
 * Extract the event window relative x/y coordinates from an event.
 * 
 * Return value: %TRUE if the event delivered event window coordinates
 **/
gboolean
gdk_event_get_coords (GdkEvent *event,
		      gdouble  *x_win,
		      gdouble  *y_win)
{
  gdouble x = 0, y = 0;
  gboolean fetched = TRUE;
  
  g_return_val_if_fail (event != NULL, FALSE);

  switch (event->type)
    {
    case GDK_CONFIGURE:
      x = event->configure.x;
      y = event->configure.y;
      break;
    case GDK_ENTER_NOTIFY:
    case GDK_LEAVE_NOTIFY:
      x = event->crossing.x;
      y = event->crossing.y;
      break;
    case GDK_SCROLL:
      x = event->scroll.x;
      y = event->scroll.y;
      break;
    case GDK_BUTTON_PRESS:
    case GDK_2BUTTON_PRESS:
    case GDK_3BUTTON_PRESS:
    case GDK_BUTTON_RELEASE:
      x = event->button.x;
      y = event->button.y;
      break;
    case GDK_MOTION_NOTIFY:
      x = event->motion.x;
      y = event->motion.y;
      break;
    default:
      fetched = FALSE;
      break;
    }

  if (x_win)
    *x_win = x;
  if (y_win)
    *y_win = x;

  return fetched;
}

/**
 * gdk_event_get_root_coords:
 * @event: a #GdkEvent
 * @x_root: location to put root window x coordinate
 * @y_root: location to put root window y coordinate
 * 
 * Extract the root window relative x/y coordinates from an event.
 * 
 * Return value: %TRUE if the event delivered root window coordinates
 **/
gboolean
gdk_event_get_root_coords (GdkEvent *event,
			   gdouble  *x_root,
			   gdouble  *y_root)
{
  gdouble x = 0, y = 0;
  gboolean fetched = TRUE;
  
  g_return_val_if_fail (event != NULL, FALSE);

  switch (event->type)
    {
    case GDK_MOTION_NOTIFY:
      x = event->motion.x_root;
      y = event->motion.y_root;
      break;
    case GDK_BUTTON_PRESS:
    case GDK_2BUTTON_PRESS:
    case GDK_3BUTTON_PRESS:
    case GDK_BUTTON_RELEASE:
      x = event->button.x_root;
      y = event->button.y_root;
      break;
    case GDK_ENTER_NOTIFY:
    case GDK_LEAVE_NOTIFY:
      x = event->crossing.x_root;
      y = event->crossing.y_root;
      break;
    case GDK_DRAG_ENTER:
    case GDK_DRAG_LEAVE:
    case GDK_DRAG_MOTION:
    case GDK_DRAG_STATUS:
    case GDK_DROP_START:
    case GDK_DROP_FINISHED:
      x = event->dnd.x_root;
      y = event->dnd.y_root;
      break;
    default:
      fetched = FALSE;
      break;
    }

  if (x_root)
    *x_root = x;
  if (y_root)
    *y_root = x;

  return fetched;
}

671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744
/**
 * gdk_event_get_axis:
 * @event: a #GdkEvent
 * @axis_use: the axis use to look for
 * @value: location to store the value found
 * 
 * Extract the axis value for a particular axis use from
 * an event structure.
 * 
 * Return value: %TRUE if the specified axis was found, otherwise %FALSE
 **/
gboolean
gdk_event_get_axis (GdkEvent   *event,
		    GdkAxisUse  axis_use,
		    gdouble    *value)
{
  gdouble *axes;
  GdkDevice *device;
  
  g_return_val_if_fail (event != NULL, FALSE);
  
  if (axis_use == GDK_AXIS_X || axis_use == GDK_AXIS_Y)
    {
      gdouble x, y;
      
      switch (event->type)
	{
	case GDK_MOTION_NOTIFY:
	  x = event->motion.x;
	  y = event->motion.y;
	  break;
	case GDK_SCROLL:
	  x = event->scroll.x;
	  y = event->scroll.y;
	  break;
	case GDK_BUTTON_PRESS:
	case GDK_BUTTON_RELEASE:
	  x = event->button.x;
	  y = event->button.y;
	  break;
	case GDK_ENTER_NOTIFY:
	case GDK_LEAVE_NOTIFY:
	  x = event->crossing.x;
	  y = event->crossing.y;
	  break;
	  
	default:
	  return FALSE;
	}

      if (axis_use == GDK_AXIS_X && value)
	*value = x;
      if (axis_use == GDK_AXIS_Y && value)
	*value = y;

      return TRUE;
    }
  else if (event->type == GDK_BUTTON_PRESS ||
	   event->type == GDK_BUTTON_RELEASE)
    {
      device = event->button.device;
      axes = event->button.axes;
    }
  else if (event->type == GDK_MOTION_NOTIFY)
    {
      device = event->motion.device;
      axes = event->motion.axes;
    }
  else
    return FALSE;

  return gdk_device_get_axis (device, axes, axis_use, value);
}

745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765
/*
 *--------------------------------------------------------------
 * gdk_set_show_events
 *
 *   Turns on/off the showing of events.
 *
 * Arguments:
 *   "show_events" is a boolean describing whether or
 *   not to show the events gdk receives.
 *
 * Results:
 *
 * Side effects:
 *   When "show_events" is TRUE, calls to "gdk_event_get"
 *   will output debugging informatin regarding the event
 *   received to stdout.
 *
 *--------------------------------------------------------------
 */

void
Owen Taylor's avatar
Owen Taylor committed
766
gdk_set_show_events (gboolean show_events)
767 768
{
  if (show_events)
769
    _gdk_debug_flags |= GDK_DEBUG_EVENTS;
770
  else
771
    _gdk_debug_flags &= ~GDK_DEBUG_EVENTS;
772 773
}

Owen Taylor's avatar
Owen Taylor committed
774
gboolean
775 776
gdk_get_show_events (void)
{
777
  return (_gdk_debug_flags & GDK_DEBUG_EVENTS) != 0;
778 779 780 781 782 783 784 785 786 787 788 789 790
}

static void
gdk_io_destroy (gpointer data)
{
  GdkIOClosure *closure = data;

  if (closure->notify)
    closure->notify (closure->data);

  g_free (closure);
}

791 792 793 794 795 796
/* What do we do with G_IO_NVAL?
 */
#define READ_CONDITION (G_IO_IN | G_IO_HUP | G_IO_ERR)
#define WRITE_CONDITION (G_IO_OUT | G_IO_ERR)
#define EXCEPTION_CONDITION (G_IO_PRI)

797 798 799 800 801 802 803 804
static gboolean  
gdk_io_invoke (GIOChannel   *source,
	       GIOCondition  condition,
	       gpointer      data)
{
  GdkIOClosure *closure = data;
  GdkInputCondition gdk_cond = 0;

805
  if (condition & READ_CONDITION)
806
    gdk_cond |= GDK_INPUT_READ;
807
  if (condition & WRITE_CONDITION)
808
    gdk_cond |= GDK_INPUT_WRITE;
809
  if (condition & EXCEPTION_CONDITION)
810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835
    gdk_cond |= GDK_INPUT_EXCEPTION;

  if (closure->condition & gdk_cond)
    closure->function (closure->data, g_io_channel_unix_get_fd (source), gdk_cond);

  return TRUE;
}

gint
gdk_input_add_full (gint	      source,
		    GdkInputCondition condition,
		    GdkInputFunction  function,
		    gpointer	      data,
		    GdkDestroyNotify  destroy)
{
  guint result;
  GdkIOClosure *closure = g_new (GdkIOClosure, 1);
  GIOChannel *channel;
  GIOCondition cond = 0;

  closure->function = function;
  closure->condition = condition;
  closure->notify = destroy;
  closure->data = data;

  if (condition & GDK_INPUT_READ)
836
    cond |= READ_CONDITION;
837
  if (condition & GDK_INPUT_WRITE)
838
    cond |= WRITE_CONDITION;
839
  if (condition & GDK_INPUT_EXCEPTION)
840
    cond |= EXCEPTION_CONDITION;
841 842

  channel = g_io_channel_unix_new (source);
843 844 845
  result = g_io_add_watch_full (channel, G_PRIORITY_DEFAULT, cond, 
				gdk_io_invoke,
				closure, gdk_io_destroy);
846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865
  g_io_channel_unref (channel);

  return result;
}

gint
gdk_input_add (gint		 source,
	       GdkInputCondition condition,
	       GdkInputFunction	 function,
	       gpointer		 data)
{
  return gdk_input_add_full (source, condition, function, data, NULL);
}

void
gdk_input_remove (gint tag)
{
  g_source_remove (tag);
}

866
GdkEvent*
867
_gdk_event_unqueue (void)
868
{
869 870
  GdkEvent *event = NULL;
  GList *tmp_list;
871

872
  tmp_list = _gdk_event_queue_find_first ();
873 874

  if (tmp_list)
875
    {
876
      event = tmp_list->data;
877
      _gdk_event_queue_remove_link (tmp_list);
878
      g_list_free_1 (tmp_list);
879
    }
880 881

  return event;
882 883
}

884
void
885 886 887 888 889 890 891 892 893 894 895 896 897
gdk_synthesize_click (GdkEvent *event,
		      gint	nclicks)
{
  GdkEvent temp_event;
  
  g_return_if_fail (event != NULL);
  
  temp_event = *event;
  temp_event.type = (nclicks == 2) ? GDK_2BUTTON_PRESS : GDK_3BUTTON_PRESS;
  
  gdk_event_put (&temp_event);
}

898
void
899
_gdk_event_button_generate (GdkEvent *event)
900
{
901 902 903
  if ((event->button.time < (button_click_time[1] + TRIPLE_CLICK_TIME)) &&
      (event->button.window == button_window[1]) &&
      (event->button.button == button_number[1]))
904
    {
905 906 907 908 909 910 911 912
      gdk_synthesize_click (event, 3);
      
      button_click_time[1] = 0;
      button_click_time[0] = 0;
      button_window[1] = NULL;
      button_window[0] = 0;
      button_number[1] = -1;
      button_number[0] = -1;
913
    }
914
  else if ((event->button.time < (button_click_time[0] + double_click_time)) &&
915 916
	   (event->button.window == button_window[0]) &&
	   (event->button.button == button_number[0]))
917
    {
918 919 920 921 922 923 924 925
      gdk_synthesize_click (event, 2);
      
      button_click_time[1] = button_click_time[0];
      button_click_time[0] = event->button.time;
      button_window[1] = button_window[0];
      button_window[0] = event->button.window;
      button_number[1] = button_number[0];
      button_number[0] = event->button.button;
926 927 928
    }
  else
    {
929 930 931 932 933 934
      button_click_time[1] = 0;
      button_click_time[0] = event->button.time;
      button_window[1] = NULL;
      button_window[0] = event->button.window;
      button_number[1] = -1;
      button_number[0] = event->button.button;
935 936
    }
}
Havoc Pennington's avatar
Havoc Pennington committed
937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989


void
gdk_synthesize_window_state (GdkWindow     *window,
                             GdkWindowState unset_flags,
                             GdkWindowState set_flags)
{
  GdkEventWindowState temp_event;
  GdkWindowState old;
  
  g_return_if_fail (window != NULL);
  
  temp_event.window = window;
  temp_event.type = GDK_WINDOW_STATE;
  temp_event.send_event = FALSE;
  
  old = ((GdkWindowObject*) temp_event.window)->state;
  
  temp_event.changed_mask = (unset_flags | set_flags) ^ old;
  temp_event.new_window_state = old;
  temp_event.new_window_state |= set_flags;
  temp_event.new_window_state &= ~unset_flags;

  if (temp_event.new_window_state == old)
    return; /* No actual work to do, nothing changed. */

  /* Actually update the field in GdkWindow, this is sort of an odd
   * place to do it, but seems like the safest since it ensures we expose no
   * inconsistent state to the user.
   */
  
  ((GdkWindowObject*) window)->state = temp_event.new_window_state;

  /* We only really send the event to toplevels, since
   * all the window states don't apply to non-toplevels.
   * Non-toplevels do use the GDK_WINDOW_STATE_WITHDRAWN flag
   * internally so we needed to update window->state.
   */
  switch (((GdkWindowObject*) window)->window_type)
    {
    case GDK_WINDOW_TOPLEVEL:
    case GDK_WINDOW_DIALOG:
    case GDK_WINDOW_TEMP: /* ? */
      gdk_event_put ((GdkEvent*) &temp_event);
      break;
      
    case GDK_WINDOW_FOREIGN:
    case GDK_WINDOW_ROOT:
    case GDK_WINDOW_CHILD:
      break;
    }
}

990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003
void
gdk_set_double_click_time (guint msec)
{
  double_click_time = msec;
}

GType
gdk_event_get_type (void)
{
  static GType our_type = 0;
  
  if (our_type == 0)
    our_type = g_boxed_type_register_static ("GdkEvent",
					     (GBoxedCopyFunc)gdk_event_copy,
1004
					     (GBoxedFreeFunc)gdk_event_free);
1005 1006
  return our_type;
}
1007 1008 1009 1010 1011 1012

GdkDevice *
gdk_device_get_core_pointer (void)
{
  return _gdk_core_pointer;
}