gdk.c 94.6 KB
Newer Older
Elliot Lee's avatar
Elliot Lee committed
1 2 3 4 5 6 7 8 9 10
/* 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
 * modify it under the terms of the GNU Library General Public
 * 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
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
Elliot Lee's avatar
Elliot Lee committed
12 13 14
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
15 16 17
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
Elliot Lee's avatar
Elliot Lee committed
18 19 20
 */
#include "../config.h"

Elliot Lee's avatar
Elliot Lee committed
21 22 23
/* If you don't want to use gdk's signal handlers define this */
/* #define I_NEED_TO_ACTUALLY_DEBUG_MY_PROGRAMS 1 */

24
#include <X11/Xlocale.h>
Elliot Lee's avatar
Elliot Lee committed
25 26 27 28 29 30
#include <ctype.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
31 32 33
#ifdef USE_XIM
#include <stdarg.h>
#endif
Elliot Lee's avatar
Elliot Lee committed
34 35 36 37 38 39 40 41 42 43 44

#ifdef HAVE_SYS_SELECT_H
#include <sys/select.h>
#endif /* HAVE_SYS_SELECT_H_ */

#define XLIB_ILLEGAL_ACCESS
#include <X11/Xatom.h>
#include <X11/Xlib.h>
#include <X11/Xos.h>
#include <X11/Xutil.h>
#include <X11/Xmu/WinUtil.h>
45 46 47
#ifdef USE_XIM
#include <X11/Xresource.h>
#endif
Elliot Lee's avatar
Elliot Lee committed
48 49 50 51
#include <X11/cursorfont.h>
#include "gdk.h"
#include "gdkprivate.h"
#include "gdkinput.h"
52
#include "gdkx.h"
rodo's avatar
rodo committed
53
#include "gdkkeysyms.h"
54
#include "gdki18n.h"
Elliot Lee's avatar
Elliot Lee committed
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70

#ifndef X_GETTIMEOFDAY
#define X_GETTIMEOFDAY(tv)  gettimeofday (tv, NULL)
#endif /* X_GETTIMEOFDAY */


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


#ifndef NO_FD_SET
#  define SELECT_MASK fd_set
#else
#  ifndef _AIX
71
typedef long fd_mask;
Elliot Lee's avatar
Elliot Lee committed
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
#  endif
#  if defined(_IBMR2)
#    define SELECT_MASK void
#  else
#    define SELECT_MASK int
#  endif
#endif


typedef struct _GdkInput      GdkInput;
typedef struct _GdkPredicate  GdkPredicate;

struct _GdkInput
{
  gint tag;
  gint source;
  GdkInputCondition condition;
  GdkInputFunction function;
  gpointer data;
91
  GdkDestroyNotify destroy;
Elliot Lee's avatar
Elliot Lee committed
92 93 94 95 96 97 98 99 100 101 102
};

struct _GdkPredicate
{
  GdkEventFunc func;
  gpointer data;
};

/* 
 * Private function declarations
 */
103

104 105 106
static GdkEvent *gdk_event_new		(void);
static gint	 gdk_event_wait		(void);
static gint	 gdk_event_apply_filters (XEvent *xevent,
107 108
					  GdkEvent *event,
					  GList *filters);
109 110
static gint	 gdk_event_translate	(GdkEvent     *event, 
					 XEvent	      *xevent);
111
#if 0
112 113
static Bool	 gdk_event_get_type	(Display      *display, 
					 XEvent	      *xevent, 
Elliot Lee's avatar
Elliot Lee committed
114
					 XPointer      arg);
115
#endif
116 117
static void	 gdk_synthesize_click	(GdkEvent     *event, 
					 gint	       nclicks);
Elliot Lee's avatar
Elliot Lee committed
118

Elliot Lee's avatar
Elliot Lee committed
119
#ifdef DEBUG_DND
120
static void	 gdk_print_atom		(GdkAtom       anatom);
Elliot Lee's avatar
Elliot Lee committed
121
#endif
Elliot Lee's avatar
Elliot Lee committed
122

123
#ifndef HAVE_XCONVERTCASE
124 125 126
static void	 gdkx_XConvertCase	(KeySym	       symbol,
					 KeySym	      *lower,
					 KeySym	      *upper);
127 128 129
#define XConvertCase gdkx_XConvertCase
#endif

Elliot Lee's avatar
Elliot Lee committed
130 131 132
/* 
 * old junk from offix, we might use it though so leave it 
 */
133 134
Window	     gdk_get_client_window   (Display	  *dpy, 
				      Window	   win);
Elliot Lee's avatar
Elliot Lee committed
135
#ifdef WE_HAVE_MOTIF_DROPS_DONE
136
static GdkWindow *  gdk_drop_get_real_window	 (GdkWindow   *w, 
Elliot Lee's avatar
Elliot Lee committed
137 138
						  guint16     *x,
						  guint16     *y);
Elliot Lee's avatar
Elliot Lee committed
139
#endif
140 141
static void	    gdk_exit_func		 (void);
static int	    gdk_x_error			 (Display     *display, 
Elliot Lee's avatar
Elliot Lee committed
142
						  XErrorEvent *error);
143 144
static int	    gdk_x_io_error		 (Display     *display);
static RETSIGTYPE   gdk_signal			 (int	       signum);
Elliot Lee's avatar
Elliot Lee committed
145 146


147
#ifdef USE_XIM
148
static guint	     gdk_im_va_count	 (va_list list);
149
static XVaNestedList gdk_im_va_to_nested (va_list list, 
150
					  guint	  count);
151

152 153 154 155 156
static GdkIM  gdk_im_get		(void);
static gint   gdk_im_open		(XrmDatabase db,
					 gchar* res_name,
					 gchar* rec_class);
static void   gdk_im_close		(void);
157
static void   gdk_ic_cleanup		(void);
158

159 160 161 162
GdkFilterReturn gdk_wm_protocols_filter (GdkXEvent *xev,
					 GdkEvent  *event,
					 gpointer   data);

163 164
#endif /* USE_XIM */

Elliot Lee's avatar
Elliot Lee committed
165 166
/* Private variable declarations
 */
167
static int gdk_initialized = 0;			    /* 1 if the library is initialized,
Elliot Lee's avatar
Elliot Lee committed
168 169
						     * 0 otherwise.
						     */
170 171 172 173 174
static int connection_number = 0;		    /* The file descriptor number of our
						     *	connection to the X server. This
						     *	is used so that we may determine
						     *	when events are pending by using
						     *	the "select" system call.
Elliot Lee's avatar
Elliot Lee committed
175 176 177
						     */


178 179
static struct timeval start;			    /* The time at which the library was
						     *	last initialized.
Elliot Lee's avatar
Elliot Lee committed
180
						     */
181 182 183 184 185
static struct timeval timer;			    /* Timeout interval to use in the call
						     *	to "select". This is used in
						     *	conjunction with "timerp" to create
						     *	a maximum time to wait for an event
						     *	to arrive.
Elliot Lee's avatar
Elliot Lee committed
186
						     */
187 188 189 190
static struct timeval *timerp;			    /* The actual timer passed to "select"
						     *	This may be NULL, in which case
						     *	"select" will block until an event
						     *	arrives.
Elliot Lee's avatar
Elliot Lee committed
191
						     */
192 193
static guint32 timer_val;			    /* The timeout length as specified by
						     *	the user in milliseconds.
Elliot Lee's avatar
Elliot Lee committed
194
						     */
195 196 197 198 199 200 201
static GList *inputs;				    /* A list of the input file descriptors
						     *	that we care about. Each list node
						     *	contains a GdkInput struct that describes
						     *	when we are interested in the specified
						     *	file descriptor. That is, when it is
						     *	available for read, write or has an
						     *	exception pending.
Elliot Lee's avatar
Elliot Lee committed
202
						     */
203 204 205
static guint32 button_click_time[2];		    /* The last 2 button click times. Used
						     *	to determine if the latest button click
						     *	is part of a double or triple click.
Elliot Lee's avatar
Elliot Lee committed
206
						     */
207 208 209
static GdkWindow *button_window[2];		    /* 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.
Elliot Lee's avatar
Elliot Lee committed
210
						     */
211
static guint button_number[2];			    /* The last 2 buttons to be pressed.
Elliot Lee's avatar
Elliot Lee committed
212
						     */
213
static GdkWindowPrivate *xgrab_window = NULL;	    /* Window that currently holds the
214
						     *	x pointer grab
215
						     */
Elliot Lee's avatar
Elliot Lee committed
216

217 218
static GList *client_filters;	                    /* Filters for client messages */

219 220 221 222 223 224 225 226 227 228 229
#ifdef USE_XIM
static gint xim_using;				/* using XIM Protocol if TRUE */
static GdkIM xim_im;				/* global IM */
static XIMStyles* xim_styles;			/* im supports these styles */
static XIMStyle xim_best_allowed_style;
static GdkICPrivate *xim_ic;			/* currently using IC */
static GdkWindow* xim_window;			/* currently using Widow */
static GList* xim_ic_list;

#endif

Elliot Lee's avatar
Elliot Lee committed
230 231 232 233 234
static GList *putback_events = NULL;

static gulong base_id;
static gint autorepeat;

235 236
#ifdef G_ENABLE_DEBUG
static GDebugKey gdk_debug_keys[] = {
237 238 239
  {"events",	    GDK_DEBUG_EVENTS},
  {"misc",	    GDK_DEBUG_MISC},
  {"dnd",	    GDK_DEBUG_DND},
240
  {"color-context", GDK_DEBUG_COLOR_CONTEXT},
241
  {"xim",	    GDK_DEBUG_XIM}
242
};
243 244 245

static const int gdk_ndebug_keys = sizeof(gdk_debug_keys)/sizeof(GDebugKey);

246
#endif /* G_ENABLE_DEBUG */
Elliot Lee's avatar
Elliot Lee committed
247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269

/*
 *--------------------------------------------------------------
 * gdk_init
 *
 *   Initialize the library for use.
 *
 * Arguments:
 *   "argc" is the number of arguments.
 *   "argv" is an array of strings.
 *
 * Results:
 *   "argc" and "argv" are modified to reflect any arguments
 *   which were not handled. (Such arguments should either
 *   be handled by the application or dismissed).
 *
 * Side effects:
 *   The library is initialized.
 *
 *--------------------------------------------------------------
 */

void
270
gdk_init (int	 *argc,
Elliot Lee's avatar
Elliot Lee committed
271 272 273
	  char ***argv)
{
  XKeyboardState keyboard_state;
274 275
  gint synchronize;
  gint i, j, k;
Elliot Lee's avatar
Elliot Lee committed
276
  XClassHint *class_hint;
277 278
  gchar **argv_orig = NULL;
  gint argc_orig = 0;
279
  
280 281
  if (gdk_initialized)
    return;
282
  
283 284 285 286 287 288 289 290 291
  if (argc && argv)
    {
      argc_orig = *argc;
      
      argv_orig = g_malloc ((argc_orig + 1) * sizeof (char*));
      for (i = 0; i < argc_orig; i++)
	argv_orig[i] = g_strdup ((*argv)[i]);
      argv_orig[argc_orig] = NULL;
    }
292
  
Elliot Lee's avatar
Elliot Lee committed
293
  X_GETTIMEOFDAY (&start);
294
  
Elliot Lee's avatar
Elliot Lee committed
295
#ifndef I_NEED_TO_ACTUALLY_DEBUG_MY_PROGRAMS
Elliot Lee's avatar
Elliot Lee committed
296 297 298 299 300 301 302
  signal (SIGHUP, gdk_signal);
  signal (SIGINT, gdk_signal);
  signal (SIGQUIT, gdk_signal);
  signal (SIGBUS, gdk_signal);
  signal (SIGSEGV, gdk_signal);
  signal (SIGPIPE, gdk_signal);
  signal (SIGTERM, gdk_signal);
Elliot Lee's avatar
Elliot Lee committed
303
#endif
304
  
Elliot Lee's avatar
Elliot Lee committed
305
  gdk_display_name = NULL;
306
  
Elliot Lee's avatar
Elliot Lee committed
307 308
  XSetErrorHandler (gdk_x_error);
  XSetIOErrorHandler (gdk_x_io_error);
309
  
Elliot Lee's avatar
Elliot Lee committed
310
  synchronize = FALSE;
311
  
312 313 314 315 316 317 318 319 320
#ifdef G_ENABLE_DEBUG
  {
    gchar *debug_string = getenv("GDK_DEBUG");
    if (debug_string != NULL)
      gdk_debug_flags = g_parse_debug_string (debug_string,
					      gdk_debug_keys,
					      gdk_ndebug_keys);
  }
#endif	/* G_ENABLE_DEBUG */
321
  
Elliot Lee's avatar
Elliot Lee committed
322 323 324
  if (argc && argv)
    {
      if (*argc > 0)
325 326
	{
	  gchar *d;
327
	  
328 329
	  d = strrchr((*argv)[0],'/');
	  if (d != NULL)
330
	    g_set_prgname (d + 1);
331
	  else
332
	    g_set_prgname ((*argv)[0]);
333
	}
334
      
Elliot Lee's avatar
Elliot Lee committed
335 336
      for (i = 1; i < *argc;)
	{
337
#ifdef G_ENABLE_DEBUG	  
338 339
	  if ((strcmp ("--gdk-debug", (*argv)[i]) == 0) ||
	      (strncmp ("--gdk-debug=", (*argv)[i], 12) == 0))
Elliot Lee's avatar
Elliot Lee committed
340
	    {
341 342 343 344 345 346 347 348 349
	      gchar *equal_pos = strchr ((*argv)[i], '=');
	      
	      if (equal_pos != NULL)
		{
		  gdk_debug_flags |= g_parse_debug_string (equal_pos+1,
							   gdk_debug_keys,
							   gdk_ndebug_keys);
		}
	      else if ((i + 1) < *argc && (*argv)[i + 1])
Elliot Lee's avatar
Elliot Lee committed
350
		{
351 352 353
		  gdk_debug_flags |= g_parse_debug_string ((*argv)[i+1],
							   gdk_debug_keys,
							   gdk_ndebug_keys);
354
		  (*argv)[i] = NULL;
355 356
		  i += 1;
		}
357
	      (*argv)[i] = NULL;
358
	    }
359 360
	  else if ((strcmp ("--gdk-no-debug", (*argv)[i]) == 0) ||
		   (strncmp ("--gdk-no-debug=", (*argv)[i], 15) == 0))
361
	    {
362
	      gchar *equal_pos = strchr ((*argv)[i], '=');
363
	      
364 365 366 367 368 369 370
	      if (equal_pos != NULL)
		{
		  gdk_debug_flags &= ~g_parse_debug_string (equal_pos+1,
							    gdk_debug_keys,
							    gdk_ndebug_keys);
		}
	      else if ((i + 1) < *argc && (*argv)[i + 1])
371 372 373 374
		{
		  gdk_debug_flags &= ~g_parse_debug_string ((*argv)[i+1],
							    gdk_debug_keys,
							    gdk_ndebug_keys);
375
		  (*argv)[i] = NULL;
Elliot Lee's avatar
Elliot Lee committed
376 377
		  i += 1;
		}
378
	      (*argv)[i] = NULL;
Elliot Lee's avatar
Elliot Lee committed
379
	    }
Owen Taylor's avatar
Owen Taylor committed
380
	  else 
381
#endif /* G_ENABLE_DEBUG */
Owen Taylor's avatar
Owen Taylor committed
382
	    if (strcmp ("--display", (*argv)[i]) == 0)
383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407
	      {
		(*argv)[i] = NULL;
		
		if ((i + 1) < *argc && (*argv)[i + 1])
		  {
		    gdk_display_name = g_strdup ((*argv)[i + 1]);
		    (*argv)[i + 1] = NULL;
		    i += 1;
		  }
	      }
	    else if (strcmp ("--sync", (*argv)[i]) == 0)
	      {
		(*argv)[i] = NULL;
		synchronize = TRUE;
	      }
	    else if (strcmp ("--no-xshm", (*argv)[i]) == 0)
	      {
		(*argv)[i] = NULL;
		gdk_use_xshm = FALSE;
	      }
	    else if (strcmp ("--name", (*argv)[i]) == 0)
	      {
		if ((i + 1) < *argc && (*argv)[i + 1])
		  {
		    (*argv)[i++] = NULL;
408
		    g_set_prgname ((*argv)[i]);
409 410 411 412 413 414 415 416 417 418 419 420
		    (*argv)[i] = NULL;
		  }
	      }
	    else if (strcmp ("--class", (*argv)[i]) == 0)
	      {
		if ((i + 1) < *argc && (*argv)[i + 1])
		  {
		    (*argv)[i++] = NULL;
		    gdk_progclass = (*argv)[i];
		    (*argv)[i] = NULL;
		  }
	      }
Elliot Lee's avatar
Elliot Lee committed
421
#ifdef XINPUT_GXI
422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439
	    else if (strcmp ("--gxid_host", (*argv)[i]) == 0)
	      {
		if ((i + 1) < *argc && (*argv)[i + 1])
		  {
		    (*argv)[i++] = NULL;
		    gdk_input_gxid_host = ((*argv)[i]);
		    (*argv)[i] = NULL;
		  }
	      }
	    else if (strcmp ("--gxid_port", (*argv)[i]) == 0)
	      {
		if ((i + 1) < *argc && (*argv)[i + 1])
		  {
		    (*argv)[i++] = NULL;
		    gdk_input_gxid_port = atoi ((*argv)[i]);
		    (*argv)[i] = NULL;
		  }
	      }
Elliot Lee's avatar
Elliot Lee committed
440
#endif
441
#ifdef USE_XIM
442 443 444 445 446 447
	    else if (strcmp ("--xim-preedit", (*argv)[i]) == 0)
	      {
		if ((i + 1) < *argc && (*argv)[i + 1])
		  {
		    (*argv)[i++] = NULL;
		    if (strcmp ("none", (*argv)[i]) == 0)
448
		      gdk_im_set_best_style (GDK_IM_PREEDIT_NONE);
449
		    else if (strcmp ("nothing", (*argv)[i]) == 0)
450
		      gdk_im_set_best_style (GDK_IM_PREEDIT_NOTHING);
451
		    else if (strcmp ("area", (*argv)[i]) == 0)
452
		      gdk_im_set_best_style (GDK_IM_PREEDIT_AREA);
453
		    else if (strcmp ("position", (*argv)[i]) == 0)
454
		      gdk_im_set_best_style (GDK_IM_PREEDIT_POSITION);
455
		    else if (strcmp ("callbacks", (*argv)[i]) == 0)
456
		      gdk_im_set_best_style (GDK_IM_PREEDIT_CALLBACKS);
457 458 459 460 461 462 463 464
		  }
	      }
	    else if (strcmp ("--xim-status", (*argv)[i]) == 0)
	      {
		if ((i + 1) < *argc && (*argv)[i + 1])
		  {
		    (*argv)[i++] = NULL;
		    if (strcmp ("none", (*argv)[i]) == 0)
465
		      gdk_im_set_best_style (GDK_IM_STATUS_NONE);
466
		    else if (strcmp ("nothing", (*argv)[i]) == 0)
467
		      gdk_im_set_best_style (GDK_IM_STATUS_NOTHING);
468
		    else if (strcmp ("area", (*argv)[i]) == 0)
469
		      gdk_im_set_best_style (GDK_IM_STATUS_AREA);
470
		    else if (strcmp ("callbacks", (*argv)[i]) == 0)
471
		      gdk_im_set_best_style (GDK_IM_STATUS_CALLBACKS);
472 473
		  }
	      }
474
#endif
475
	  
Elliot Lee's avatar
Elliot Lee committed
476 477
	  i += 1;
	}
478
      
Elliot Lee's avatar
Elliot Lee committed
479 480 481 482 483
      for (i = 1; i < *argc; i++)
	{
	  for (k = i; k < *argc; k++)
	    if ((*argv)[k] != NULL)
	      break;
484
	  
Elliot Lee's avatar
Elliot Lee committed
485 486 487 488 489 490 491 492 493 494 495
	  if (k > i)
	    {
	      k -= i;
	      for (j = i + k; j < *argc; j++)
		(*argv)[j-k] = (*argv)[j];
	      *argc -= k;
	    }
	}
    }
  else
    {
496
      g_set_prgname ("<unknown>");
Elliot Lee's avatar
Elliot Lee committed
497
    }
498
  
499
  GDK_NOTE (MISC, g_message ("progname: \"%s\"", g_get_prgname ()));
500
  
Elliot Lee's avatar
Elliot Lee committed
501 502
  gdk_display = XOpenDisplay (gdk_display_name);
  if (!gdk_display)
503 504 505 506
    {
      g_warning ("cannot open display: %s", XDisplayName (gdk_display_name));
      exit(1);
    }
507
  
Elliot Lee's avatar
Elliot Lee committed
508 509 510 511 512 513
  /* This is really crappy. We have to look into the display structure
   *  to find the base resource id. This is only needed for recording
   *  and playback of events.
   */
  /* base_id = RESOURCE_BASE; */
  base_id = 0;
514 515
  GDK_NOTE (EVENTS, g_message ("base id: %lu", base_id));
  
Elliot Lee's avatar
Elliot Lee committed
516
  connection_number = ConnectionNumber (gdk_display);
517
  GDK_NOTE (MISC,
518 519
	    g_message ("connection number: %d", connection_number));
  
Elliot Lee's avatar
Elliot Lee committed
520 521
  if (synchronize)
    XSynchronize (gdk_display, True);
522
  
Elliot Lee's avatar
Elliot Lee committed
523 524
  gdk_screen = DefaultScreen (gdk_display);
  gdk_root_window = RootWindow (gdk_display, gdk_screen);
525
  
Elliot Lee's avatar
Elliot Lee committed
526 527 528
  gdk_leader_window = XCreateSimpleWindow(gdk_display, gdk_root_window,
					  10, 10, 10, 10, 0, 0 , 0);
  class_hint = XAllocClassHint();
529
  class_hint->res_name = g_get_prgname ();
530 531
  if (gdk_progclass == NULL)
    {
532
      gdk_progclass = g_strdup (g_get_prgname ());
533 534
      gdk_progclass[0] = toupper (gdk_progclass[0]);
    }
Elliot Lee's avatar
Elliot Lee committed
535 536 537 538
  class_hint->res_class = gdk_progclass;
  XSetClassHint(gdk_display, gdk_leader_window, class_hint);
  XSetCommand(gdk_display, gdk_leader_window, argv_orig, argc_orig);
  XFree (class_hint);
539 540 541 542 543
  
  for (i = 0; i < argc_orig; i++)
    g_free(argv_orig[i]);
  g_free(argv_orig);
  
Elliot Lee's avatar
Elliot Lee committed
544 545 546 547 548 549
  gdk_wm_delete_window = XInternAtom (gdk_display, "WM_DELETE_WINDOW", True);
  gdk_wm_take_focus = XInternAtom (gdk_display, "WM_TAKE_FOCUS", True);
  gdk_wm_protocols = XInternAtom (gdk_display, "WM_PROTOCOLS", True);
  gdk_wm_window_protocols[0] = gdk_wm_delete_window;
  gdk_wm_window_protocols[1] = gdk_wm_take_focus;
  gdk_selection_property = XInternAtom (gdk_display, "GDK_SELECTION", False);
550
  
Elliot Lee's avatar
Elliot Lee committed
551 552
  XGetKeyboardControl (gdk_display, &keyboard_state);
  autorepeat = keyboard_state.global_auto_repeat;
553
  
Elliot Lee's avatar
Elliot Lee committed
554 555 556
  timer.tv_sec = 0;
  timer.tv_usec = 0;
  timerp = NULL;
557
  
Elliot Lee's avatar
Elliot Lee committed
558 559 560 561 562 563
  button_click_time[0] = 0;
  button_click_time[1] = 0;
  button_window[0] = NULL;
  button_window[1] = NULL;
  button_number[0] = -1;
  button_number[1] = -1;
564
  
Tim Janik's avatar
Tim Janik committed
565
  g_atexit (gdk_exit_func);
566
  
Elliot Lee's avatar
Elliot Lee committed
567 568 569 570
  gdk_visual_init ();
  gdk_window_init ();
  gdk_image_init ();
  gdk_input_init ();
571 572 573 574
  gdk_dnd_init ();

  gdk_add_client_message_filter (gdk_wm_protocols, 
				 gdk_wm_protocols_filter, NULL);
575
  
576 577 578 579 580
#ifdef USE_XIM
  /* initialize XIM Protocol variables */
  xim_using = FALSE;
  xim_im = NULL;
  xim_styles = NULL;
581 582 583 584
  if (!(xim_best_allowed_style & GDK_IM_PREEDIT_MASK))
    gdk_im_set_best_style (GDK_IM_PREEDIT_CALLBACKS);
  if (!(xim_best_allowed_style & GDK_IM_STATUS_MASK))
    gdk_im_set_best_style (GDK_IM_STATUS_CALLBACKS);
585 586
  xim_ic = NULL;
  xim_window = (GdkWindow*)NULL;
587
  
588 589
  gdk_im_open (NULL, NULL, NULL);
#endif
590
  
591
  gdk_initialized = 1;
Elliot Lee's avatar
Elliot Lee committed
592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615
}

/*
 *--------------------------------------------------------------
 * gdk_exit
 *
 *   Restores the library to an un-itialized state and exits
 *   the program using the "exit" system call.
 *
 * Arguments:
 *   "errorcode" is the error value to pass to "exit".
 *
 * Results:
 *   Allocated structures are freed and the program exits
 *   cleanly.
 *
 * Side effects:
 *
 *--------------------------------------------------------------
 */

void
gdk_exit (int errorcode)
{
616 617 618
  /* de-initialisation is done by the gdk_exit_funct(),
     no need to do this here (Alex J.) */
  exit (errorcode);
Elliot Lee's avatar
Elliot Lee committed
619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634
}

/*
 *--------------------------------------------------------------
 * gdk_set_locale
 *
 * Arguments:
 *
 * Results:
 *
 * Side effects:
 *
 *--------------------------------------------------------------
 */

gchar*
635
gdk_set_locale (void)
Elliot Lee's avatar
Elliot Lee committed
636 637
{
  if (!setlocale (LC_ALL,""))
638 639
    g_message ("locale not supported by C library");
  
Elliot Lee's avatar
Elliot Lee committed
640 641
  if (!XSupportsLocale ())
    {
642
      g_message ("locale not supported by Xlib, locale set to C");
Elliot Lee's avatar
Elliot Lee committed
643 644
      setlocale (LC_ALL, "C");
    }
645
  
Elliot Lee's avatar
Elliot Lee committed
646 647
  if (!XSetLocaleModifiers (""))
    {
648
      g_message ("can not set locale modifiers");
Elliot Lee's avatar
Elliot Lee committed
649
    }
650
  
Elliot Lee's avatar
Elliot Lee committed
651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672
  return setlocale (LC_ALL,NULL);
}

/*
 *--------------------------------------------------------------
 * gdk_events_pending
 *
 *   Returns the number of events pending on the queue.
 *   These events have already been read from the server
 *   connection.
 *
 * Arguments:
 *
 * Results:
 *   Returns the number of events on XLib's event queue.
 *
 * Side effects:
 *
 *--------------------------------------------------------------
 */

gint
673
gdk_events_pending (void)
Elliot Lee's avatar
Elliot Lee committed
674
{
Owen Taylor's avatar
Owen Taylor committed
675 676
  gint result;
  GList *tmp_list;
677
  
Owen Taylor's avatar
Owen Taylor committed
678
  result = XPending (gdk_display);
679
  
Owen Taylor's avatar
Owen Taylor committed
680 681 682 683 684 685 686 687
  tmp_list = putback_events;
  while (tmp_list)
    {
      result++;
      tmp_list = tmp_list->next;
    }
  
  return result;
Elliot Lee's avatar
Elliot Lee committed
688 689
}

690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711
/*
 *--------------------------------------------------------------
 * gdk_event_get_graphics_expose
 *
 *   Waits for a GraphicsExpose or NoExpose event
 *
 * Arguments:
 *
 * Results: 
 *   For GraphicsExpose events, returns a pointer to the event
 *   converted into a GdkEvent Otherwise, returns NULL.
 *
 * Side effects:
 *
 *-------------------------------------------------------------- */

static Bool
graphics_expose_predicate  (Display  *display,
			    XEvent   *xevent,
			    XPointer  arg)
{
  GdkWindowPrivate *private = (GdkWindowPrivate *)arg;
712 713
  
  g_return_val_if_fail (private != NULL, False);
714
  
715 716 717 718 719 720 721 722 723 724 725 726 727
  if ((xevent->xany.window == private->xwindow) &&
      ((xevent->xany.type == GraphicsExpose) ||
       (xevent->xany.type == NoExpose)))
    return True;
  else
    return False;
}

GdkEvent *
gdk_event_get_graphics_expose (GdkWindow *window)
{
  XEvent xevent;
  GdkEvent *event;
728 729
  
  g_return_val_if_fail (window != NULL, NULL);
730
  
731
  XIfEvent (gdk_display, &xevent, graphics_expose_predicate, (XPointer)window);
732
  
733 734 735
  if (xevent.xany.type == GraphicsExpose)
    {
      event = gdk_event_new ();
736
      
737 738 739 740 741 742
      if (gdk_event_translate (event, &xevent))
	return event;
      else
	gdk_event_free (event);
    }
  
743
  return NULL;	
744 745
}

Elliot Lee's avatar
Elliot Lee committed
746 747 748 749 750 751 752 753 754
/*
 *--------------------------------------------------------------
 * gdk_event_get
 *
 *   Gets the next event.
 *
 * Arguments:
 *
 * Results:
755 756 757
 *   If an event was received that we care about, returns 
 *   a pointer to that event, to be freed with gdk_event_free.
 *   Otherwise, returns NULL. This function will also return
Elliot Lee's avatar
Elliot Lee committed
758 759 760 761 762 763 764 765
 *   before an event is received if the timeout interval
 *   runs out.
 *
 * Side effects:
 *
 *--------------------------------------------------------------
 */

766 767
GdkEvent *
gdk_event_get (void)
Elliot Lee's avatar
Elliot Lee committed
768
{
769
  GdkEvent *event;
Elliot Lee's avatar
Elliot Lee committed
770 771
  GList *temp_list;
  XEvent xevent;
772
  
773
#if 0
Elliot Lee's avatar
Elliot Lee committed
774 775 776 777 778 779
  if (pred)
    {
      temp_list = putback_events;
      while (temp_list)
	{
	  temp_event = temp_list->data;
780
	  
Elliot Lee's avatar
Elliot Lee committed
781 782 783 784 785 786 787 788
	  if ((* pred) (temp_event, data))
	    {
	      if (event)
		*event = *temp_event;
	      putback_events = g_list_remove_link (putback_events, temp_list);
	      g_list_free (temp_list);
	      return TRUE;
	    }
789
	  
Elliot Lee's avatar
Elliot Lee committed
790 791
	  temp_list = temp_list->next;
	}
792
      
Elliot Lee's avatar
Elliot Lee committed
793 794
      event_pred.func = pred;
      event_pred.data = data;
795
      
796
      if (XCheckIfEvent (gdk_display, &xevent, gdk_event_get_type, (XPointer) & event_pred))
Elliot Lee's avatar
Elliot Lee committed
797 798 799 800
	if (event)
	  return gdk_event_translate (event, &xevent);
    }
  else
801
#endif
802 803 804 805 806 807 808 809 810 811
    if (putback_events)
      {
	event = putback_events->data;
	
	temp_list = putback_events;
	putback_events = g_list_remove_link (putback_events, temp_list);
	g_list_free_1 (temp_list);
	
	return event;
      }
812 813 814 815 816 817 818 819 820 821
  
  /* Wait for an event to occur or the timeout to elapse.
   * If an event occurs "gdk_event_wait" will return TRUE.
   *  If the timeout elapses "gdk_event_wait" will return
   *  FALSE.
   */
  if (gdk_event_wait ())
    {
      /* If we get here we can rest assurred that an event
       *  has occurred. Read it.
Elliot Lee's avatar
Elliot Lee committed
822
       */
823
#ifdef USE_XIM
824 825 826 827
      gint filter_status;
      if (xim_using && xim_window)
	do
	  {		/* don't dispatch events used by IM */
828
	    XNextEvent (gdk_display, &xevent);
829 830 831 832 833
	    filter_status = XFilterEvent (&xevent, 
					  GDK_WINDOW_XWINDOW (xim_window));
	  } while (filter_status == True);
      else
	XNextEvent (gdk_display, &xevent);
834
#else
835
      XNextEvent (gdk_display, &xevent);
836
#endif
837
      event = gdk_event_new ();
838
      
839 840 841 842 843 844 845 846 847
      event->any.type = GDK_NOTHING;
      event->any.window = NULL;
      event->any.send_event = FALSE;
      event->any.send_event = xevent.xany.send_event;
      
      if (gdk_event_translate (event, &xevent))
	return event;
      else
	gdk_event_free (event);
Elliot Lee's avatar
Elliot Lee committed
848
    }
849
  
850
  return NULL;
Elliot Lee's avatar
Elliot Lee committed
851 852 853 854 855 856
}

void
gdk_event_put (GdkEvent *event)
{
  GdkEvent *new_event;
857
  
Elliot Lee's avatar
Elliot Lee committed
858
  g_return_if_fail (event != NULL);
859
  
860
  new_event = gdk_event_copy (event);
861
  
Elliot Lee's avatar
Elliot Lee committed
862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884
  putback_events = g_list_prepend (putback_events, new_event);
}

/*
 *--------------------------------------------------------------
 * 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.
 *
 *--------------------------------------------------------------
 */

static GMemChunk *event_chunk;

885 886
static GdkEvent*
gdk_event_new (void)
Elliot Lee's avatar
Elliot Lee committed
887 888 889 890 891 892 893 894
{
  GdkEvent *new_event;
  
  if (event_chunk == NULL)
    event_chunk = g_mem_chunk_new ("events",
				   sizeof (GdkEvent),
				   4096,
				   G_ALLOC_AND_FREE);
895
  
Elliot Lee's avatar
Elliot Lee committed
896
  new_event = g_chunk_new (GdkEvent, event_chunk);
897
  
898 899 900 901 902 903 904 905 906
  return new_event;
}

GdkEvent*
gdk_event_copy (GdkEvent *event)
{
  GdkEvent *new_event;
  
  g_return_val_if_fail (event != NULL, NULL);
907
  
908
  new_event = gdk_event_new ();
909
  
Elliot Lee's avatar
Elliot Lee committed
910 911
  *new_event = *event;
  gdk_window_ref (new_event->any.window);
912
  
Owen Taylor's avatar
Owen Taylor committed
913 914 915 916 917 918
  switch (event->any.type)
    {
    case GDK_KEY_PRESS:
    case GDK_KEY_RELEASE:
      new_event->key.string = g_strdup (event->key.string);
      break;
919
      
Owen Taylor's avatar
Owen Taylor committed
920 921 922 923 924
    case GDK_ENTER_NOTIFY:
    case GDK_LEAVE_NOTIFY:
      if (event->crossing.subwindow != NULL)
	gdk_window_ref (event->crossing.subwindow);
      break;
925
      
926 927 928 929 930 931 932
    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);
Owen Taylor's avatar
Owen Taylor committed
933
      break;
934

935
      
Owen Taylor's avatar
Owen Taylor committed
936 937 938
    default:
      break;
    }
939
  
Elliot Lee's avatar
Elliot Lee committed
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
  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_assert (event_chunk != NULL);
  g_return_if_fail (event != NULL);
966
  
967 968
  if (event->any.window)
    gdk_window_unref (event->any.window);
969
  
Owen Taylor's avatar
Owen Taylor committed
970 971 972 973 974 975
  switch (event->any.type)
    {
    case GDK_KEY_PRESS:
    case GDK_KEY_RELEASE:
      g_free (event->key.string);
      break;
976
      
Owen Taylor's avatar
Owen Taylor committed
977 978 979 980 981
    case GDK_ENTER_NOTIFY:
    case GDK_LEAVE_NOTIFY:
      if (event->crossing.subwindow != NULL)
	gdk_window_unref (event->crossing.subwindow);
      break;
982
      
983 984 985 986 987 988 989
    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);
Elliot Lee's avatar
Elliot Lee committed
990
      break;
991

992
      
Owen Taylor's avatar
Owen Taylor committed
993 994 995
    default:
      break;
    }
996
  
Elliot Lee's avatar
Elliot Lee committed
997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019
  g_mem_chunk_free (event_chunk, event);
}

/*
 *--------------------------------------------------------------
 * 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.
 *
 *--------------------------------------------------------------
 */

1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073
/*
 *--------------------------------------------------------------
 * gdk_event_get_time:
 *    Get the timestamp from an event.
 *   arguments:
 *     event:
 *   results:
 *    The event's time stamp, if it has one, otherwise
 *    GDK_CURRENT_TIME.
 *--------------------------------------------------------------
 */

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;
      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;
      default:			/* use current time */
	break;
      }
  
  return GDK_CURRENT_TIME;
}

Elliot Lee's avatar
Elliot Lee committed
1074 1075 1076
void
gdk_set_show_events (int show_events)
{
1077 1078 1079 1080
  if (show_events)
    gdk_debug_flags |= GDK_DEBUG_EVENTS;
  else
    gdk_debug_flags &= ~GDK_DEBUG_EVENTS;
Elliot Lee's avatar
Elliot Lee committed
1081 1082 1083 1084 1085 1086 1087 1088 1089
}

void
gdk_set_use_xshm (gint use_xshm)
{
  gdk_use_xshm = use_xshm;
}

gint
1090
gdk_get_show_events (void)
Elliot Lee's avatar
Elliot Lee committed
1091
{
1092
  return gdk_debug_flags & GDK_DEBUG_EVENTS;
Elliot Lee's avatar
Elliot Lee committed
1093 1094 1095
}

gint
1096
gdk_get_use_xshm (void)
Elliot Lee's avatar
Elliot Lee committed
1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121
{
  return gdk_use_xshm;
}

/*
 *--------------------------------------------------------------
 * gdk_time_get
 *
 *   Get the number of milliseconds since the library was
 *   initialized.
 *
 * Arguments:
 *
 * Results:
 *   The time since the library was initialized is returned.
 *   This time value is accurate to milliseconds even though
 *   a more accurate time down to the microsecond could be
 *   returned.
 *
 * Side effects:
 *
 *--------------------------------------------------------------
 */

guint32
1122
gdk_time_get (void)
Elliot Lee's avatar
Elliot Lee committed
1123 1124 1125 1126
{
  struct timeval end;
  struct timeval elapsed;
  guint32 milliseconds;
1127
  
Elliot Lee's avatar
Elliot Lee committed
1128
  X_GETTIMEOFDAY (&end);
1129
  
Elliot Lee's avatar
Elliot Lee committed
1130 1131 1132 1133 1134 1135 1136
  if (start.tv_usec > end.tv_usec)
    {
      end.tv_usec += 1000000;
      end.tv_sec--;
    }
  elapsed.tv_sec = end.tv_sec - start.tv_sec;
  elapsed.tv_usec = end.tv_usec - start.tv_usec;
1137
  
Elliot Lee's avatar
Elliot Lee committed
1138
  milliseconds = (elapsed.tv_sec * 1000) + (elapsed.tv_usec / 1000);
1139
  
Elliot Lee's avatar
Elliot Lee committed
1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160
  return milliseconds;
}

/*
 *--------------------------------------------------------------
 * gdk_timer_get
 *
 *   Returns the current timer.
 *
 * Arguments:
 *
 * Results:
 *   Returns the current timer interval. This interval is
 *   in units of milliseconds.
 *
 * Side effects:
 *
 *--------------------------------------------------------------
 */

guint32
1161
gdk_timer_get (void)
Elliot Lee's avatar
Elliot Lee committed
1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191
{
  return timer_val;
}

/*
 *--------------------------------------------------------------
 * gdk_timer_set
 *
 *   Sets the timer interval.
 *
 * Arguments:
 *   "milliseconds" is the new value for the timer.
 *
 * Results:
 *
 * Side effects:
 *   Calls to "gdk_event_get" will last for a maximum
 *   of time of "milliseconds". However, a value of 0
 *   milliseconds will cause "gdk_event_get" to block
 *   indefinately until an event is received.
 *
 *--------------------------------------------------------------
 */

void
gdk_timer_set (guint32 milliseconds)
{
  timer_val = milliseconds;
  timer.tv_sec = milliseconds / 1000;
  timer.tv_usec = (milliseconds % 1000) * 1000;
1192
  
Elliot Lee's avatar
Elliot Lee committed
1193 1194 1195
}

void
1196
gdk_timer_enable (void)
Elliot Lee's avatar
Elliot Lee committed
1197 1198 1199 1200 1201
{
  timerp = &timer;
}

void
1202
gdk_timer_disable (void)
Elliot Lee's avatar
Elliot Lee committed
1203 1204 1205 1206 1207
{
  timerp = NULL;
}

gint
1208
gdk_input_add_full (gint	      source,
1209 1210
		    GdkInputCondition condition,
		    GdkInputFunction  function,
1211
		    gpointer	      data,
1212
		    GdkDestroyNotify  destroy)
Elliot Lee's avatar
Elliot Lee committed
1213 1214 1215 1216 1217
{
  static gint next_tag = 1;
  GList *list;
  GdkInput *input;
  gint tag;
1218
  
Elliot Lee's avatar
Elliot Lee committed
1219 1220
  tag = 0;
  list = inputs;
1221
  
Elliot Lee's avatar
Elliot Lee committed
1222 1223 1224 1225
  while (list)
    {
      input = list->data;
      list = list->next;
1226
      
Elliot Lee's avatar
Elliot Lee committed
1227 1228
      if ((input->source == source) && (input->condition == condition))
	{
1229 1230
	  if (input->destroy)
	    (input->destroy) (input->data);
Elliot Lee's avatar
Elliot Lee committed
1231 1232
	  input->function = function;
	  input->data = data;
1233
	  input->destroy = destroy;
Elliot Lee's avatar
Elliot Lee committed
1234 1235 1236
	  tag = input->tag;
	}
    }
1237
  
Elliot Lee's avatar
Elliot Lee committed
1238 1239 1240 1241 1242 1243 1244 1245
  if (!tag)
    {
      input = g_new (GdkInput, 1);
      input->tag = next_tag++;
      input->source = source;
      input->condition = condition;
      input->function = function;
      input->data = data;
1246
      input->destroy = destroy;
Elliot Lee's avatar
Elliot Lee committed
1247
      tag = input->tag;
1248
      
Elliot Lee's avatar
Elliot Lee committed
1249 1250
      inputs = g_list_prepend (inputs, input);
    }
1251
  
Elliot Lee's avatar
Elliot Lee committed
1252 1253 1254
  return tag;
}

1255
gint
1256
gdk_input_add (gint		 source,
1257
	       GdkInputCondition condition,
1258 1259
	       GdkInputFunction	 function,
	       gpointer		 data)
Owen Taylor's avatar