gdkevents-x11.c 69.8 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
29
#include "gdkprivate-x11.h"
#include "gdkinternals.h"
Owen Taylor's avatar
Started    
Owen Taylor committed
30
#include "gdkx.h"
31
32
#include "gdkscreen-x11.h"
#include "gdkdisplay-x11.h"
Owen Taylor's avatar
Started    
Owen Taylor committed
33

34
35
#include "gdkkeysyms.h"

36
37
#include "xsettings-client.h"

38
39
40
41
42
43
44
#if HAVE_CONFIG_H
#  include <config.h>
#  if STDC_HEADERS
#    include <string.h>
#  endif
#endif

Owen Taylor's avatar
Started    
Owen Taylor committed
45
#include "gdkinputprivate.h"
46

Havoc Pennington's avatar
Havoc Pennington committed
47
48
49
50
#ifdef HAVE_XKB
#include <X11/XKBlib.h>
#endif

Havoc Pennington's avatar
Havoc Pennington committed
51
52
#include <X11/Xatom.h>

53
typedef struct _GdkIOClosure GdkIOClosure;
54
typedef struct _GdkDisplaySource GdkDisplaySource;
55
56
57
58
59
60

#define DOUBLE_CLICK_TIME      250
#define TRIPLE_CLICK_TIME      500
#define DOUBLE_CLICK_DIST      5
#define TRIPLE_CLICK_DIST      5

61
62
struct _GdkIOClosure
{
63
64
65
66
67
68
  GdkInputFunction function;
  GdkInputCondition condition;
  GdkDestroyNotify notify;
  gpointer data;
};

69
70
71
72
73
74
75
76
struct _GdkDisplaySource
{
  GSource source;
  
  GdkDisplay *display;
  GPollFD event_poll_fd;
};

77
78
79
80
/* 
 * Private function declarations
 */

81
static gint	 gdk_event_apply_filters (XEvent   *xevent,
82
					  GdkEvent *event,
83
					  GList    *filters);
84
85
86
87
static gboolean	 gdk_event_translate	 (GdkDisplay *display,
					  GdkEvent   *event, 
					  XEvent     *xevent,
					  gboolean    return_exposes);
88

89
90
91
92
93
94
static gboolean gdk_event_prepare  (GSource     *source,
				    gint        *timeout);
static gboolean gdk_event_check    (GSource     *source);
static gboolean gdk_event_dispatch (GSource     *source,
				    GSourceFunc  callback,
				    gpointer     user_data);
95

96
97
98
static GdkFilterReturn gdk_wm_protocols_filter (GdkXEvent *xev,
						GdkEvent  *event,
						gpointer   data);
99

100
101
102
static GSource *gdk_display_source_new (GdkDisplay *display);
static gboolean gdk_check_xpending     (GdkDisplay *display);

103
104
105
106
107
108
109
110
111
static void gdk_xsettings_watch_cb  (Window            window,
				     Bool              is_start,
				     long              mask,
				     void             *cb_data);
static void gdk_xsettings_notify_cb (const char       *name,
				     XSettingsAction   action,
				     XSettingsSetting *setting,
				     void             *data);

112
113
114
/* Private variable declarations
 */

115
static GList *display_sources;
116
117
118
119
120

static GSourceFuncs event_funcs = {
  gdk_event_prepare,
  gdk_event_check,
  gdk_event_dispatch,
121
  NULL
122
123
};

124
125
126
127
128
129
130
131
132
133
static GSource *
gdk_display_source_new (GdkDisplay *display)
{
  GSource *source = g_source_new (&event_funcs, sizeof (GdkDisplaySource));
  GdkDisplaySource *display_source = (GdkDisplaySource *)source;
  
  display_source->display = display;
  
  return source;
}
134

135
136
137
138
139
static gboolean
gdk_check_xpending (GdkDisplay *display)
{
  return XPending (GDK_DISPLAY_XDISPLAY (display));
}
140

141
142
143
144
/*********************************************
 * Functions for maintaining the event queue *
 *********************************************/

145
146
147
148
void
_gdk_x11_events_init_screen (GdkScreen *screen)
{
  GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
149
150
151
152

  /* Keep a flag to avoid extra notifies that we don't need
   */
  screen_x11->xsettings_in_init = TRUE;
153
154
155
156
157
  screen_x11->xsettings_client = xsettings_client_new (screen_x11->xdisplay,
						       screen_x11->screen_num,
						       gdk_xsettings_notify_cb,
						       gdk_xsettings_watch_cb,
						       screen);
158
  screen_x11->xsettings_in_init = FALSE;
159
160
}

161
162
163
164
165
166
167
168
169
void
_gdk_x11_events_uninit_screen (GdkScreen *screen)
{
  GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);

  xsettings_client_destroy (screen_x11->xsettings_client);
  screen_x11->xsettings_client = NULL;
}

170
void 
171
_gdk_events_init (GdkDisplay *display)
172
{
173
  GSource *source;
174
175
  GdkDisplaySource *display_source;
  GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
176
  
177
178
  int connection_number = ConnectionNumber (display_x11->xdisplay);
  GDK_NOTE (MISC, g_message ("connection number: %d", connection_number));
179
180


181
  source = display_x11->event_source = gdk_display_source_new (display);
182
  display_source = (GdkDisplaySource*) source;
183
184
  g_source_set_priority (source, GDK_PRIORITY_EVENTS);
  
185
186
  display_source->event_poll_fd.fd = connection_number;
  display_source->event_poll_fd.events = G_IO_IN;
187
  
188
  g_source_add_poll (source, &display_source->event_poll_fd);
189
190
  g_source_set_can_recurse (source, TRUE);
  g_source_attach (source, NULL);
191

192
193
194
195
196
197
198
  display_sources = g_list_prepend (display_sources,display_source);

  gdk_display_add_client_message_filter (
	display,
	gdk_atom_intern ("WM_PROTOCOLS", FALSE), 
	gdk_wm_protocols_filter,   
	NULL);
199
200
201
}


202
203
204
205
206
207
208
/**
 * gdk_events_pending:
 * 
 * Checks if any events are ready to be processed for any display.
 * 
 * Return value:  %TRUE if any events are pending.
 **/
209
gboolean
210
211
gdk_events_pending (void)
{
212
  GList *tmp_list;
213

214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
  for (tmp_list = display_sources; tmp_list; tmp_list = tmp_list->next)
    {
      GdkDisplaySource *tmp_source = tmp_list->data;
      GdkDisplay *display = tmp_source->display;
      
      if (_gdk_event_queue_find_first (display))
	return TRUE;
    }

  for (tmp_list = display_sources; tmp_list; tmp_list = tmp_list->next)
    {
      GdkDisplaySource *tmp_source = tmp_list->data;
      GdkDisplay *display = tmp_source->display;
      
      if (gdk_check_xpending (display))
	return TRUE;
    }
  
  return FALSE;
}
234
235

static Bool
236
237
238
graphics_expose_predicate (Display  *display,
			   XEvent   *xevent,
			   XPointer  arg)
239
{
240
  if (xevent->xany.window == GDK_DRAWABLE_XID ((GdkDrawable *)arg) &&
241
242
      (xevent->xany.type == GraphicsExpose ||
       xevent->xany.type == NoExpose))
243
244
245
246
247
    return True;
  else
    return False;
}

248
249
250
251
252
253
254
255
256
257
258
/**
 * gdk_event_get_graphics_expose:
 * @window: the #GdkWindow to wait for the events for.
 * 
 * Waits for a GraphicsExpose or NoExpose event from the X server.
 * This is used in the #GtkText and #GtkCList widgets in GTK+ to make sure any
 * GraphicsExpose events are handled before the widget is scrolled.
 *
 * Return value:  a #GdkEventExpose if a GraphicsExpose was received, or %NULL if a
 * NoExpose event was received.
 **/
259
GdkEvent*
260
261
262
263
264
265
266
gdk_event_get_graphics_expose (GdkWindow *window)
{
  XEvent xevent;
  GdkEvent *event;
  
  g_return_val_if_fail (window != NULL, NULL);
  
267
268
  XIfEvent (GDK_WINDOW_XDISPLAY (window), &xevent, 
	    graphics_expose_predicate, (XPointer) window);
269
270
271
  
  if (xevent.xany.type == GraphicsExpose)
    {
272
      event = _gdk_event_new ();
273
      
274
275
      if (gdk_event_translate (GDK_WINDOW_DISPLAY (window), event,
			       &xevent, TRUE))
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
	return event;
      else
	gdk_event_free (event);
    }
  
  return NULL;	
}

static gint
gdk_event_apply_filters (XEvent *xevent,
			 GdkEvent *event,
			 GList *filters)
{
  GList *tmp_list;
  GdkFilterReturn result;
  
  tmp_list = filters;
  
  while (tmp_list)
    {
296
      GdkEventFilter *filter = (GdkEventFilter*) tmp_list->data;
297
      
298
299
      tmp_list = tmp_list->next;
      result = filter->function (xevent, event, filter->data);
300
301
302
303
304
305
306
      if (result !=  GDK_FILTER_CONTINUE)
	return result;
    }
  
  return GDK_FILTER_CONTINUE;
}

307
308
309
310
311
312
313
314
315
316
317
318
/**
 * gdk_display_add_client_message_filter:
 * @display: a #GdkDisplay for which this message filter applies
 * @message_type: the type of ClientMessage events to receive.
 *   This will be checked against the @message_type field 
 *   of the XClientMessage event struct.
 * @func: the function to call to process the event.
 * @data: user data to pass to @func.
 *
 * Adds a filter to be called when X ClientMessage events are received.
 *
 **/ 
319
void 
320
321
322
323
gdk_display_add_client_message_filter (GdkDisplay   *display,
				       GdkAtom       message_type,
				       GdkFilterFunc func,
				       gpointer      data)
324
{
325
326
327
  GdkClientFilter *filter;
  g_return_if_fail (GDK_IS_DISPLAY (display));
  filter = g_new (GdkClientFilter, 1);
328
329
330
331
332

  filter->type = message_type;
  filter->function = func;
  filter->data = data;
  
333
334
335
  GDK_DISPLAY_X11(display)->client_filters = 
    g_list_prepend (GDK_DISPLAY_X11 (display)->client_filters,
		    filter);
336
337
}

338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
/**
 * gdk_add_client_message_filter:
 * @message_type: the type of ClientMessage events to receive. This will be
 *     checked against the <structfield>message_type</structfield> field of the
 *     XClientMessage event struct.
 * @func: the function to call to process the event.
 * @data: user data to pass to @func. 
 * 
 * Adds a filter to the default display to be called when X ClientMessage events
 * are received. See gdk_display_add_client_message_filter().
 **/
void 
gdk_add_client_message_filter (GdkAtom       message_type,
			       GdkFilterFunc func,
			       gpointer      data)
{
Owen Taylor's avatar
Owen Taylor committed
354
  gdk_display_add_client_message_filter (gdk_display_get_default (),
355
356
					 message_type, func, data);
}
Havoc Pennington's avatar
Havoc Pennington committed
357
358
359
360
361
362
363
364

static void
gdk_check_wm_state_changed (GdkWindow *window)
{  
  Atom type;
  gint format;
  gulong nitems;
  gulong bytes_after;
365
  Atom *atoms = NULL;
Havoc Pennington's avatar
Havoc Pennington committed
366
  gulong i;
367
  gboolean found_sticky, found_maxvert, found_maxhorz, found_fullscreen;
Havoc Pennington's avatar
Havoc Pennington committed
368
  GdkWindowState old_state;
369
  GdkDisplay *display = GDK_WINDOW_DISPLAY (window);
Havoc Pennington's avatar
Havoc Pennington committed
370
  
371
372
  if (GDK_WINDOW_DESTROYED (window) ||
      gdk_window_get_window_type (window) != GDK_WINDOW_TOPLEVEL)
Havoc Pennington's avatar
Havoc Pennington committed
373
374
    return;
  
375
376
377
  found_sticky = FALSE;
  found_maxvert = FALSE;
  found_maxhorz = FALSE;
378
  found_fullscreen = FALSE;
Havoc Pennington's avatar
Havoc Pennington committed
379
380
  
  XGetWindowProperty (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window),
381
382
		      gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE"),
		      0, G_MAXLONG, False, XA_ATOM, &type, &format, &nitems,
Havoc Pennington's avatar
Havoc Pennington committed
383
384
385
386
		      &bytes_after, (guchar **)&atoms);

  if (type != None)
    {
387
388
389
      Atom sticky_atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE_STICKY");
      Atom maxvert_atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE_MAXIMIZED_VERT");
      Atom maxhorz_atom	= gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE_MAXIMIZED_HORZ");
390
391
      Atom fullscreen_atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE_FULLSCREEN");
      
Havoc Pennington's avatar
Havoc Pennington committed
392
393
394
395
396
397
398
399
400
      i = 0;
      while (i < nitems)
        {
          if (atoms[i] == sticky_atom)
            found_sticky = TRUE;
          else if (atoms[i] == maxvert_atom)
            found_maxvert = TRUE;
          else if (atoms[i] == maxhorz_atom)
            found_maxhorz = TRUE;
401
402
403
          else if (atoms[i] == fullscreen_atom)
            found_fullscreen = TRUE;
          
Havoc Pennington's avatar
Havoc Pennington committed
404
405
406
407
408
409
410
411
412
413
414
415
416
417
          ++i;
        }

      XFree (atoms);
    }

  /* For found_sticky to remain TRUE, we have to also be on desktop
   * 0xFFFFFFFF
   */

  if (found_sticky)
    {
      gulong *desktop;
      
418
419
420
421
422
423
      XGetWindowProperty (GDK_WINDOW_XDISPLAY (window), 
			  GDK_WINDOW_XID (window),
                          gdk_x11_get_xatom_by_name_for_display 
			  (display, "_NET_WM_DESKTOP"),
			  0, G_MAXLONG, False, XA_CARDINAL, &type, 
			  &format, &nitems,
Havoc Pennington's avatar
Havoc Pennington committed
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
                          &bytes_after, (guchar **)&desktop);

      if (type != None)
        {
          if (*desktop != 0xFFFFFFFF)
            found_sticky = FALSE;
          XFree (desktop);
        }
    }
          
  old_state = gdk_window_get_state (window);

  if (old_state & GDK_WINDOW_STATE_STICKY)
    {
      if (!found_sticky)
        gdk_synthesize_window_state (window,
                                     GDK_WINDOW_STATE_STICKY,
                                     0);
    }
  else
    {
      if (found_sticky)
        gdk_synthesize_window_state (window,
                                     0,
                                     GDK_WINDOW_STATE_STICKY);
    }

451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
  if (old_state & GDK_WINDOW_STATE_FULLSCREEN)
    {
      if (!found_fullscreen)
        gdk_synthesize_window_state (window,
                                     GDK_WINDOW_STATE_FULLSCREEN,
                                     0);
    }
  else
    {
      if (found_fullscreen)
        gdk_synthesize_window_state (window,
                                     0,
                                     GDK_WINDOW_STATE_FULLSCREEN);
    }
  
Havoc Pennington's avatar
Havoc Pennington committed
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
  /* Our "maximized" means both vertical and horizontal; if only one,
   * we don't expose that via GDK
   */
  if (old_state & GDK_WINDOW_STATE_MAXIMIZED)
    {
      if (!(found_maxvert && found_maxhorz))
        gdk_synthesize_window_state (window,
                                     GDK_WINDOW_STATE_MAXIMIZED,
                                     0);
    }
  else
    {
      if (found_maxvert && found_maxhorz)
        gdk_synthesize_window_state (window,
                                     0,
                                     GDK_WINDOW_STATE_MAXIMIZED);
    }
}

485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
#define HAS_FOCUS(window_impl)                           \
  ((window_impl)->has_focus || (window_impl)->has_pointer_focus)

static void
generate_focus_event (GdkWindow *window,
		      gboolean   in)
{
  GdkEvent event;
  
  event.type = GDK_FOCUS_CHANGE;
  event.focus_change.window = window;
  event.focus_change.send_event = FALSE;
  event.focus_change.in = in;
  
  gdk_event_put (&event);
}

502
503
504
505
506
507
508
509
510
511
512
513
514
static void
set_screen_from_root (GdkDisplay *display,
		      GdkEvent   *event,
		      Window      xrootwin)
{
  GdkScreen *screen;

  screen = _gdk_x11_display_screen_for_xrootwin (display, xrootwin);
  g_assert (screen);

  gdk_event_set_screen (event, screen);
}

515
516
517
518
519
static gboolean
gdk_event_translate (GdkDisplay *display,
		     GdkEvent   *event,
		     XEvent     *xevent,
		     gboolean    return_exposes)
520
521
522
{
  
  GdkWindow *window;
523
  GdkWindowObject *window_private;
524
  GdkWindowImplX11 *window_impl = NULL;
525
526
527
528
529
  static XComposeStatus compose;
  KeySym keysym;
  int charcount;
  char buf[16];
  gint return_val;
530
  gint xoffset, yoffset;
531
532
533
  GdkScreen *screen = NULL;
  GdkScreenX11 *screen_x11 = NULL;
  GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
534
535
  
  return_val = FALSE;
536
537
538
539
540

  /* init these, since the done: block uses them */
  window = NULL;
  window_private = NULL;
  event->any.window = NULL;
541

542
  if (_gdk_default_filters)
543
544
545
546
    {
      /* Apply global filters */
      GdkFilterReturn result;
      result = gdk_event_apply_filters (xevent, event,
547
                                        _gdk_default_filters);
548
549
550
551
552
553
554
555
556
557
558
559
560
      
      if (result != GDK_FILTER_CONTINUE)
        {
          return_val = (result == GDK_FILTER_TRANSLATE) ? TRUE : FALSE;
          goto done;
        }
    }  

   /* We handle events with window=None
    *  specially - they are generated by XFree86's XInput under
    *  some circumstances. This handling for obvious reasons
    * goes before we bother to lookup the event window.
    */
561
  
562
  if (xevent->xany.window == None)
563
    {
564
      return_val = _gdk_input_window_none_event (event, xevent);
565
566
567
568
569
570
      
      if (return_val >= 0)	/* was handled */
	return return_val;
      else
	return_val = FALSE;
    }
571
572

  /* Find the GdkWindow that this event occurred in. */
573
  
574
  window = gdk_window_lookup_for_display (display, xevent->xany.window);
575
  window_private = (GdkWindowObject *) window;
576
577
578
579
580
581
582

  if (window)
    {
      screen = GDK_WINDOW_SCREEN (window);
      screen_x11 = GDK_SCREEN_X11 (screen);
    }
    
583
584
  if (window != NULL)
    {
585
586
587
588
589
590
591
592
      /* Window may be a pixmap, so check its type.
       * (This check is probably too expensive unless
       *  GLib short-circuits an exact type match,
       *  which has been proposed)
       */
      if (GDK_IS_WINDOW (window))
        {
          window_impl = GDK_WINDOW_IMPL_X11 (window_private->impl);
593
	  
594
595
596
597
598
599
600
601
602
603
604
          if (xevent->xany.window != GDK_WINDOW_XID (window))
            {
              g_assert (xevent->xany.window == window_impl->focus_window);
              
              switch (xevent->type)
                {
                case KeyPress:
                case KeyRelease:
                  xevent->xany.window = GDK_WINDOW_XID (window);
                  break;
                default:
605
                  return FALSE;
606
607
608
                }
            }
        }
609

610
      g_object_ref (window);
611
612
    }

613
  event->any.window = window;
614
  event->any.send_event = xevent->xany.send_event ? TRUE : FALSE;
615
  
616
  if (window_private && GDK_WINDOW_DESTROYED (window))
617
618
    {
      if (xevent->type != DestroyNotify)
619
620
621
622
	{
	  return_val = FALSE;
	  goto done;
	}
623
    }
624
  else if (window_private)
625
    {
626
      /* Apply per-window filters */
627
628
      GdkFilterReturn result;
      result = gdk_event_apply_filters (xevent, event,
629
					window_private->filters);
630
631
632
      
      if (result != GDK_FILTER_CONTINUE)
	{
Owen Taylor's avatar
Owen Taylor committed
633
634
	  return_val = (result == GDK_FILTER_TRANSLATE) ? TRUE : FALSE;
	  goto done;
635
636
	}
    }
637
      
638
639
  if (screen_x11 && screen_x11->wmspec_check_window != None &&
      xevent->xany.window == screen_x11->wmspec_check_window)
640
641
    {
      if (xevent->type == DestroyNotify)
642
643
644
645
646
647
648
649
        {
          screen_x11->wmspec_check_window = None;
          g_free (screen_x11->window_manager_name);
          screen_x11->window_manager_name = g_strdup ("unknown");

          /* careful, reentrancy */
          _gdk_x11_screen_window_manager_changed (GDK_SCREEN (screen_x11));
        }
650
651
652
653
654
      
      /* Eat events on this window unless someone had wrapped
       * it as a foreign window
       */
      if (window == NULL)
655
656
657
658
	{
	  return_val = FALSE;
	  goto done;
	}
659
    }
660

661
662
663
664
  if (window &&
      (xevent->xany.type == MotionNotify ||
       xevent->xany.type == ButtonRelease))
    {
665
666
667
668
669
      if (_gdk_moveresize_handle_event (xevent))
	{
          return_val = FALSE;
          goto done;
        }
670
671
    }
  
672
673
674
675
676
677
678
679
680
  /* We do a "manual" conversion of the XEvent to a
   *  GdkEvent. The structures are mostly the same so
   *  the conversion is fairly straightforward. We also
   *  optionally print debugging info regarding events
   *  received.
   */

  return_val = TRUE;

681
682
683
684
685
686
687
688
689
  if (window)
    {
      _gdk_windowing_window_get_offsets (window, &xoffset, &yoffset);
    }
  else
    {
      xoffset = 0;
      yoffset = 0;
    }
690

691
692
693
  switch (xevent->type)
    {
    case KeyPress:
694
695
696
697
698
699
      if (window_private == NULL)
        {
          return_val = FALSE;
          break;
        }
      
700
701
      /* Lookup the string corresponding to the given keysym.
       */
702

703
704
705
      charcount = XLookupString (&xevent->xkey, buf, 16,
				 &keysym, &compose);
      event->key.keyval = keysym;
Havoc Pennington's avatar
Havoc Pennington committed
706
      event->key.hardware_keycode = xevent->xkey.keycode;
707
708
709
710
711
712
713
      
      if (charcount > 0 && buf[charcount-1] == '\0')
	charcount --;
      else
	buf[charcount] = '\0';
      
#ifdef G_ENABLE_DEBUG
714
      if (_gdk_debug_flags & GDK_DEBUG_EVENTS)
715
716
717
718
719
720
721
722
723
724
	{
	  g_message ("key press:\twindow: %ld  key: %12s  %d",
		     xevent->xkey.window,
		     event->key.keyval ? XKeysymToString (event->key.keyval) : "(none)",
		     event->key.keyval);
	  if (charcount > 0)
	    g_message ("\t\tlength: %4d string: \"%s\"",
		       charcount, buf);
	}
#endif /* G_ENABLE_DEBUG */
Havoc Pennington's avatar
Havoc Pennington committed
725

726
727
728
729
730
731
      event->key.type = GDK_KEY_PRESS;
      event->key.window = window;
      event->key.time = xevent->xkey.time;
      event->key.state = (GdkModifierType) xevent->xkey.state;
      event->key.string = g_strdup (buf);
      event->key.length = charcount;
Havoc Pennington's avatar
Havoc Pennington committed
732

733
734
735
736
      /* bits 13 and 14 in the "state" field are the keyboard group */
#define KEYBOARD_GROUP_SHIFT 13
#define KEYBOARD_GROUP_MASK ((1 << 13) | (1 << 14))
      
737
      event->key.group = _gdk_x11_get_group_for_state (display, xevent->xkey.state);
738
739
740
741
      
      break;
      
    case KeyRelease:
742
743
744
745
746
747
      if (window_private == NULL)
        {
          return_val = FALSE;
          break;
        }
      
748
749
      /* Lookup the string corresponding to the given keysym.
       */
750
751
752
753
754
755

      /* Emulate detectable auto-repeat by checking to see
       * if the next event is a key press with the same
       * keycode and timestamp, and if so, ignoring the event.
       */

756
      if (!display_x11->have_xkb_autorepeat && XPending (xevent->xkey.display))
757
758
759
	{
	  XEvent next_event;

760
	  XPeekEvent (xevent->xkey.display, &next_event);
761
762
763
764
765
766
767

	  if (next_event.type == KeyPress &&
	      next_event.xkey.keycode == xevent->xkey.keycode &&
	      next_event.xkey.time == xevent->xkey.time)
	    break;
	}
      
768
769
770
771
      keysym = GDK_VoidSymbol;
      charcount = XLookupString (&xevent->xkey, buf, 16,
				 &keysym, &compose);
      event->key.keyval = keysym;      
772
      event->key.hardware_keycode = xevent->xkey.keycode;
773
774
775
776
777
778
779
780
781
782
783
784
785
786
      
      GDK_NOTE (EVENTS, 
		g_message ("key release:\t\twindow: %ld	 key: %12s  %d",
			   xevent->xkey.window,
			   XKeysymToString (event->key.keyval),
			   event->key.keyval));
      
      event->key.type = GDK_KEY_RELEASE;
      event->key.window = window;
      event->key.time = xevent->xkey.time;
      event->key.state = (GdkModifierType) xevent->xkey.state;
      event->key.length = 0;
      event->key.string = NULL;
      
787
788
      event->key.group = (xevent->xkey.state & KEYBOARD_GROUP_MASK) >> KEYBOARD_GROUP_SHIFT;

789
790
791
792
793
794
795
796
797
      break;
      
    case ButtonPress:
      GDK_NOTE (EVENTS, 
		g_message ("button press:\t\twindow: %ld  x,y: %d %d  button: %d",
			   xevent->xbutton.window,
			   xevent->xbutton.x, xevent->xbutton.y,
			   xevent->xbutton.button));
      
798
799
      if (window_private == NULL || 
	  ((window_private->extension_events != 0) &&
800
           display_x11->input_ignore_core))
801
802
803
804
805
	{
	  return_val = FALSE;
	  break;
	}
      
806
807
      /* If we get a ButtonPress event where the button is 4 or 5,
	 it's a Scroll event */
808
809
810
811
812
813
      switch (xevent->xbutton.button)
        {
        case 4: /* up */
        case 5: /* down */
        case 6: /* left */
        case 7: /* right */
814
	  event->scroll.type = GDK_SCROLL;
815
816
817
818
819
820
821
822
823
824

          if (xevent->xbutton.button == 4)
            event->scroll.direction = GDK_SCROLL_UP;
          else if (xevent->xbutton.button == 5)
            event->scroll.direction = GDK_SCROLL_DOWN;
          else if (xevent->xbutton.button == 6)
            event->scroll.direction = GDK_SCROLL_LEFT;
          else
            event->scroll.direction = GDK_SCROLL_RIGHT;

825
	  event->scroll.window = window;
826
	  event->scroll.time = xevent->xbutton.time;
827
828
	  event->scroll.x = xevent->xbutton.x + xoffset;
	  event->scroll.y = xevent->xbutton.y + yoffset;
829
830
831
	  event->scroll.x_root = (gfloat)xevent->xbutton.x_root;
	  event->scroll.y_root = (gfloat)xevent->xbutton.y_root;
	  event->scroll.state = (GdkModifierType) xevent->xbutton.state;
832
	  event->scroll.device = display->core_pointer;
833
834
835

	  set_screen_from_root (display, event, xevent->xbutton.root);
	  
836
837
838
          break;
          
        default:
839
840
841
	  event->button.type = GDK_BUTTON_PRESS;
	  event->button.window = window;
	  event->button.time = xevent->xbutton.time;
842
843
	  event->button.x = xevent->xbutton.x + xoffset;
	  event->button.y = xevent->xbutton.y + yoffset;
844
845
	  event->button.x_root = (gfloat)xevent->xbutton.x_root;
	  event->button.y_root = (gfloat)xevent->xbutton.y_root;
846
	  event->button.axes = NULL;
847
848
	  event->button.state = (GdkModifierType) xevent->xbutton.state;
	  event->button.button = xevent->xbutton.button;
849
	  event->button.device = display->core_pointer;
850
	  
851
852
	  set_screen_from_root (display, event, xevent->xbutton.root);

853
	  _gdk_event_button_generate (display, event);
854
          break;
855
	}
856
857
858
859
860
861
862
863
864
865

      break;
      
    case ButtonRelease:
      GDK_NOTE (EVENTS, 
		g_message ("button release:\twindow: %ld  x,y: %d %d  button: %d",
			   xevent->xbutton.window,
			   xevent->xbutton.x, xevent->xbutton.y,
			   xevent->xbutton.button));
      
866
867
      if (window_private == NULL ||
	  ((window_private->extension_events != 0) &&
868
           display_x11->input_ignore_core))
869
870
871
872
873
	{
	  return_val = FALSE;
	  break;
	}
      
874
      /* We treat button presses as scroll wheel events, so ignore the release */
875
876
      if (xevent->xbutton.button == 4 || xevent->xbutton.button == 5 ||
          xevent->xbutton.button == 6 || xevent->xbutton.button ==7)
877
878
879
880
881
	{
	  return_val = FALSE;
	  break;
	}

882
883
884
      event->button.type = GDK_BUTTON_RELEASE;
      event->button.window = window;
      event->button.time = xevent->xbutton.time;
885
886
      event->button.x = xevent->xbutton.x + xoffset;
      event->button.y = xevent->xbutton.y + yoffset;
887
888
      event->button.x_root = (gfloat)xevent->xbutton.x_root;
      event->button.y_root = (gfloat)xevent->xbutton.y_root;
889
      event->button.axes = NULL;
890
891
      event->button.state = (GdkModifierType) xevent->xbutton.state;
      event->button.button = xevent->xbutton.button;
892
      event->button.device = display->core_pointer;
893
894

      set_screen_from_root (display, event, xevent->xbutton.root);
895
896
897
898
899
900
901
902
903
904
      
      break;
      
    case MotionNotify:
      GDK_NOTE (EVENTS,
		g_message ("motion notify:\t\twindow: %ld  x,y: %d %d  hint: %s", 
			   xevent->xmotion.window,
			   xevent->xmotion.x, xevent->xmotion.y,
			   (xevent->xmotion.is_hint) ? "true" : "false"));
      
905
906
      if (window_private == NULL ||
	  ((window_private->extension_events != 0) &&
907
           display_x11->input_ignore_core))
908
909
910
911
912
913
914
915
	{
	  return_val = FALSE;
	  break;
	}
      
      event->motion.type = GDK_MOTION_NOTIFY;
      event->motion.window = window;
      event->motion.time = xevent->xmotion.time;
916
917
      event->motion.x = xevent->xmotion.x + xoffset;
      event->motion.y = xevent->xmotion.y + yoffset;
918
919
      event->motion.x_root = (gfloat)xevent->xmotion.x_root;
      event->motion.y_root = (gfloat)xevent->xmotion.y_root;
920
      event->motion.axes = NULL;
921
922
      event->motion.state = (GdkModifierType) xevent->xmotion.state;
      event->motion.is_hint = xevent->xmotion.is_hint;
923
      event->motion.device = display->core_pointer;
924
      
925
926
      set_screen_from_root (display, event, xevent->xmotion.root);
      
927
928
929
930
931
932
933
934
      break;
      
    case EnterNotify:
      GDK_NOTE (EVENTS,
		g_message ("enter notify:\t\twindow: %ld  detail: %d subwin: %ld",
			   xevent->xcrossing.window,
			   xevent->xcrossing.detail,
			   xevent->xcrossing.subwindow));
935
936
937
938
939
940
941
 
      if (window_private == NULL)
        {
          return_val = FALSE;
          break;
        }
      
942
      /* Handle focusing (in the case where no window manager is running */
943
944
      if (window &&
	  GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD &&
945
946
947
948
949
950
951
952
953
954
955
	  xevent->xcrossing.detail != NotifyInferior &&
	  xevent->xcrossing.focus && !window_impl->has_focus)
	{
	  gboolean had_focus = HAS_FOCUS (window_impl);
	  
	  window_impl->has_pointer_focus = TRUE;

	  if (HAS_FOCUS (window_impl) != had_focus)
	    generate_focus_event (window, TRUE);
	}

956
957
      /* Tell XInput stuff about it if appropriate */
      if (window_private &&
958
	  !GDK_WINDOW_DESTROYED (window) &&
959
960
	  window_private->extension_events != 0)
	_gdk_input_enter_event (&xevent->xcrossing, window);
961
962
963
964
965
966
967
968
      
      event->crossing.type = GDK_ENTER_NOTIFY;
      event->crossing.window = window;
      
      /* If the subwindow field of the XEvent is non-NULL, then
       *  lookup the corresponding GdkWindow.
       */
      if (xevent->xcrossing.subwindow != None)
969
	event->crossing.subwindow = gdk_window_lookup_for_display (display, xevent->xcrossing.subwindow);
970
971
972
973
      else
	event->crossing.subwindow = NULL;
      
      event->crossing.time = xevent->xcrossing.time;
974
975
      event->crossing.x = xevent->xcrossing.x + xoffset;
      event->crossing.y = xevent->xcrossing.y + yoffset;
976
977
978
      event->crossing.x_root = xevent->xcrossing.x_root;
      event->crossing.y_root = xevent->xcrossing.y_root;
      
979
980
      set_screen_from_root (display, event, xevent->xcrossing.root);
      
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
      /* Translate the crossing mode into Gdk terms.
       */
      switch (xevent->xcrossing.mode)
	{
	case NotifyNormal:
	  event->crossing.mode = GDK_CROSSING_NORMAL;
	  break;
	case NotifyGrab:
	  event->crossing.mode = GDK_CROSSING_GRAB;
	  break;
	case NotifyUngrab:
	  event->crossing.mode = GDK_CROSSING_UNGRAB;
	  break;
	};
      
      /* Translate the crossing detail into Gdk terms.
       */
      switch (xevent->xcrossing.detail)
	{
	case NotifyInferior: