diff options
author | Elliot Lee <sopwith@src.gnome.org> | 1997-11-24 22:37:52 +0000 |
---|---|---|
committer | Elliot Lee <sopwith@src.gnome.org> | 1997-11-24 22:37:52 +0000 |
commit | 9508b76bd2401b6b9e289b5c8ec9fc0e08909283 (patch) | |
tree | 53c88a9e5ac09e1a027e56df33bdaa66d670901b /gdk | |
download | gdk-pixbuf-9508b76bd2401b6b9e289b5c8ec9fc0e08909283.tar.gz |
Initial revision
Diffstat (limited to 'gdk')
57 files changed, 24318 insertions, 0 deletions
diff --git a/gdk/.cvsignore b/gdk/.cvsignore new file mode 100644 index 000000000..79680c82c --- /dev/null +++ b/gdk/.cvsignore @@ -0,0 +1,6 @@ +*.lo +Makefile +.deps +_libs +libgdk.la + diff --git a/gdk/Makefile.am b/gdk/Makefile.am new file mode 100644 index 000000000..f298e2c3a --- /dev/null +++ b/gdk/Makefile.am @@ -0,0 +1,75 @@ +## Process this file with automake to produce Makefile.in + +gdkincludedir = $(includedir)/gdk + +lib_LTLIBRARIES = libgdk.la + +libgdk_la_SOURCES = \ + gdk.c \ + gdkcolor.c \ + gdkcursor.c \ + gdkdraw.c \ + gdkfont.c \ + gdkgc.c \ + gdkglobals.c \ + gdkimage.c \ + gdkinput.c \ + gdkpixmap.c \ + gdkproperty.c \ + gdkrectangle.c \ + gdkselection.c \ + gdkvisual.c \ + gdkwindow.c \ + gdkxid.c \ + gxid_lib.c +## this last one is ifdef'd out unless XINPUT_GXI is defined +## It's easier than trying to get automake to handle compiling +## it conditionally + +gdkinclude_HEADERS = \ + gdk.h \ + gdkcursors.h \ + gdkkeysyms.h \ + gdkprivate.h \ + gdktypes.h \ + gdkinput.h \ + gdkinputnone.h \ + gdkinputcommon.h\ + gdkinputgxi.h \ + gdkinputxfree.h \ + gxid_lib.h \ + gxid_proto.h \ + gdkx.h + +libgdk_la_LDFLAGS = -version-info 1:0:0 \ + @x_ldflags@ @x_libs@ + +INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/glib @x_cflags@ + +EXTRA_PROGRAMS = gxid + +bin_PROGRAMS = @xinput_progs@ + +gxid_SOURCES = gxid.c + +gxid_LDADD = \ + @x_ldflags@ \ + @x_libs@ \ + -lm + +BUILT_SOURCES = gdkcursors.h gdkkeysyms.h + +EXTRA_DIST = makecursors makecursors.sed makekeysyms makekeysyms.sed + +gdkcursors.h: + $(srcdir)/makecursors @x_includes@/X11/cursorfont.h > $@ + +gdkkeysyms.h: + $(srcdir)/makekeysyms @x_includes@/X11/keysymdef.h > $@ + +.PHONY: files + +files: + @files=`ls $(DISTFILES) 2> /dev/null `; for p in $$files; do \ + echo $$p; \ + done diff --git a/gdk/gdk.c b/gdk/gdk.c new file mode 100644 index 000000000..d5f85dd1e --- /dev/null +++ b/gdk/gdk.c @@ -0,0 +1,2897 @@ +/* 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 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include "../config.h" + +#include <ctype.h> +#include <locale.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <limits.h> + +#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> +#include <X11/cursorfont.h> +#include "gdk.h" +#include "gdkprivate.h" +#include "gdkinput.h" + + +#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 + typedef long fd_mask; +# 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; +}; + +struct _GdkPredicate +{ + GdkEventFunc func; + gpointer data; +}; + +/* + * Private function declarations + */ +static gint gdk_event_wait (void); +static gint gdk_event_translate (GdkEvent *event, + XEvent *xevent); +static Bool gdk_event_get_type (Display *display, + XEvent *xevent, + XPointer arg); +static void gdk_synthesize_click (GdkEvent *event, + gint nclicks); + +static void gdk_dnd_drag_begin (GdkWindow *initial_window); +static void gdk_dnd_drag_enter (Window dest); +static void gdk_dnd_drag_leave (Window dest); +static void gdk_dnd_drag_end (Window dest, + GdkPoint coords); +static GdkAtom gdk_dnd_check_types (GdkWindow *window, + XEvent *xevent); +static void gdk_print_atom (GdkAtom anatom); + +/* + * old junk from offix, we might use it though so leave it + */ +static Window gdk_drop_get_client_window (Display *dpy, + Window win); +static GdkWindow * gdk_drop_get_real_window (GdkWindow *w, + guint16 *x, + guint16 *y); +static void gdk_exit_func (void); +static int gdk_x_error (Display *display, + XErrorEvent *error); +static int gdk_x_io_error (Display *display); +static RETSIGTYPE gdk_signal (int signum); + + +/* Private variable declarations + */ +static int initialized = 0; /* 1 if the library is initialized, + * 0 otherwise. + */ +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. + */ + +static gint received_destroy_notify = FALSE; /* Did we just receive a destroy notify + * event? If so, we need to actually + * destroy the window which received + * it now. + */ +static GdkWindow *window_to_destroy = NULL; /* If we previously received a destroy + * notify event then this is the window + * which received that event. + */ + +static struct timeval start; /* The time at which the library was + * last initialized. + */ +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. + */ +static struct timeval *timerp; /* The actual timer passed to "select" + * This may be NULL, in which case + * "select" will block until an event + * arrives. + */ +static guint32 timer_val; /* The timeout length as specified by + * the user in milliseconds. + */ +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. + */ +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. + */ +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. + */ +static guint button_number[2]; /* The last 2 buttons to be pressed. + */ + +#define OTHER_XEVENT_BUFSIZE 4 +static XEvent other_xevent[OTHER_XEVENT_BUFSIZE]; /* XEvents passed along to user */ +static int other_xevent_i = 0; +static GList *putback_events = NULL; + +static gulong base_id; +static gint autorepeat; + + +/* + *-------------------------------------------------------------- + * 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 +gdk_init (int *argc, + char ***argv) +{ + XKeyboardState keyboard_state; + int synchronize; + int i, j, k; + XClassHint *class_hint; + int argc_orig = *argc; + char **argv_orig; + + argv_orig = 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; + + X_GETTIMEOFDAY (&start); + + 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); + + gdk_display_name = NULL; + + XSetErrorHandler (gdk_x_error); + XSetIOErrorHandler (gdk_x_io_error); + + synchronize = FALSE; + + if (argc && argv) + { + if (*argc > 0) + gdk_progname = (*argv)[0]; + + for (i = 1; i < *argc;) + { + if (strcmp ("--display", (*argv)[i]) == 0) + { + (*argv)[i] = NULL; + + if ((i + 1) < *argc) + { + 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 ("--show-events", (*argv)[i]) == 0) + { + (*argv)[i] = NULL; + gdk_show_events = TRUE; + } + else if (strcmp ("--no-show-events", (*argv)[i]) == 0) + { + (*argv)[i] = NULL; + gdk_show_events = FALSE; + } + else if (strcmp ("--no-xshm", (*argv)[i]) == 0) + { + (*argv)[i] = NULL; + gdk_use_xshm = FALSE; + } + else if (strcmp ("--debug-level", (*argv)[i]) == 0) + { + if ((i + 1) < *argc) + { + (*argv)[i++] = NULL; + gdk_debug_level = atoi ((*argv)[i]); + (*argv)[i] = NULL; + } + } + else if (strcmp ("-name", (*argv)[i]) == 0) + { + if ((i + 1) < *argc) + { + (*argv)[i++] = NULL; + gdk_progname = (*argv)[i]; + (*argv)[i] = NULL; + } + } + else if (strcmp ("-class", (*argv)[i]) == 0) + { + if ((i + 1) < *argc) + { + (*argv)[i++] = NULL; + gdk_progclass = (*argv)[i]; + (*argv)[i] = NULL; + } + } +#ifdef XINPUT_GXI + else if (strcmp ("--gxid_host", (*argv)[i]) == 0) + { + if ((i + 1) < *argc) + { + (*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++] = NULL; + gdk_input_gxid_port = atoi ((*argv)[i]); + (*argv)[i] = NULL; + } + } +#endif + i += 1; + } + + for (i = 1; i < *argc; i++) + { + for (k = i; k < *argc; k++) + if ((*argv)[k] != NULL) + break; + + if (k > i) + { + k -= i; + for (j = i + k; j < *argc; j++) + (*argv)[j-k] = (*argv)[j]; + *argc -= k; + } + } + } + else + { + gdk_progname = "<unknown>"; + } + + gdk_display = XOpenDisplay (gdk_display_name); + if (!gdk_display) + g_error ("cannot open display: %s", XDisplayName (gdk_display_name)); + + /* 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; + if (gdk_show_events) + g_print ("base id: %lu\n", base_id); + + connection_number = ConnectionNumber (gdk_display); + if (gdk_debug_level >= 1) + g_print ("connection number: %d\n", connection_number); + + if (synchronize) + XSynchronize (gdk_display, True); + + gdk_screen = DefaultScreen (gdk_display); + gdk_root_window = RootWindow (gdk_display, gdk_screen); + + gdk_leader_window = XCreateSimpleWindow(gdk_display, gdk_root_window, + 10, 10, 10, 10, 0, 0 , 0); + class_hint = XAllocClassHint(); + class_hint->res_name = gdk_progname; + 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); + + 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); + + gdk_dnd.gdk_XdeEnter = gdk_atom_intern("_XDE_ENTER", FALSE); + gdk_dnd.gdk_XdeLeave = gdk_atom_intern("_XDE_LEAVE", FALSE); + gdk_dnd.gdk_XdeRequest = gdk_atom_intern("_XDE_REQUEST", FALSE); + gdk_dnd.gdk_XdeDataAvailable = gdk_atom_intern("_XDE_DATA_AVAILABLE", FALSE); + gdk_dnd.gdk_XdeTypelist = gdk_atom_intern("_XDE_TYPELIST", FALSE); + gdk_dnd.gdk_cursor_dragdefault = XCreateFontCursor(gdk_display, XC_bogosity); + gdk_dnd.gdk_cursor_dragok = XCreateFontCursor(gdk_display, XC_heart); + + XGetKeyboardControl (gdk_display, &keyboard_state); + autorepeat = keyboard_state.global_auto_repeat; + + timer.tv_sec = 0; + timer.tv_usec = 0; + timerp = NULL; + + 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; + + if (ATEXIT (gdk_exit_func)) + g_warning ("unable to register exit function"); + + gdk_visual_init (); + gdk_window_init (); + gdk_image_init (); + gdk_input_init (); + + initialized = 1; +} + +/* + *-------------------------------------------------------------- + * 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) +{ + /* de-initialisation is done by the gdk_exit_funct(), + no need to do this here (Alex J.) */ + exit (errorcode); +} + +/* + *-------------------------------------------------------------- + * gdk_set_locale + * + * Arguments: + * + * Results: + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +gchar* +gdk_set_locale () +{ + if (!setlocale (LC_ALL,"")) + g_print ("locale not supported by C library\n"); + + if (!XSupportsLocale ()) + { + g_print ("locale not supported by Xlib, locale set to C\n"); + setlocale (LC_ALL, "C"); + } + + if (!XSetLocaleModifiers ("")) + { + g_print ("can not set locale modifiers\n"); + } + + 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 +gdk_events_pending () +{ + return XPending (gdk_display); +} + +/* + *-------------------------------------------------------------- + * gdk_event_get + * + * Gets the next event. + * + * Arguments: + * "event" is used to hold the received event. + * If "event" is NULL an event is received as normal + * however it is not placed in "event" (and thus no + * error occurs). + * + * Results: + * Returns TRUE if an event was received that we care about + * and FALSE otherwise. This function will also return + * before an event is received if the timeout interval + * runs out. + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +gint +gdk_event_get (GdkEvent *event, + GdkEventFunc pred, + gpointer data) +{ + GdkEvent *temp_event; + GdkPredicate event_pred; + GList *temp_list; + XEvent xevent; + + /* If the last event we received was a destroy notify + * event then we will actually destroy the "gdk" data + * structures now. We don't want to destroy them at the + * time of receiving the event since the main program + * may try to access them and may need to destroy user + * data that has been attached to the window + */ + if (received_destroy_notify) + { + if (gdk_show_events) + g_print ("destroying window:\twindow: %ld\n", + ((GdkWindowPrivate*) window_to_destroy)->xwindow - base_id); + + gdk_window_real_destroy (window_to_destroy); + received_destroy_notify = FALSE; + window_to_destroy = NULL; + } + + /* Initially we haven't received an event and want to + * return FALSE. If "event" is non-NULL, then initialize + * it to the nothing event. + */ + if (event) + { + event->any.type = GDK_NOTHING; + event->any.window = NULL; + event->any.send_event = FALSE; + } + + if (pred) + { + temp_list = putback_events; + while (temp_list) + { + temp_event = temp_list->data; + + 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; + } + + temp_list = temp_list->next; + } + + event_pred.func = pred; + event_pred.data = data; + + if (XCheckIfEvent (gdk_display, &xevent, gdk_event_get_type, (XPointer) &event_pred)) + if (event) + return gdk_event_translate (event, &xevent); + } + else + { + if (putback_events) + { + temp_event = putback_events->data; + *event = *temp_event; + + temp_list = putback_events; + putback_events = putback_events->next; + if (putback_events) + putback_events->prev = NULL; + + temp_list->next = NULL; + temp_list->prev = NULL; + g_list_free (temp_list); + g_free (temp_event); + + return TRUE; + } + + /* 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. + */ + XNextEvent (gdk_display, &xevent); + + event->any.send_event = xevent.xany.send_event; + + /* If "event" non-NULL. + */ + if (event) + return gdk_event_translate (event, &xevent); + } + } + + return FALSE; +} + +void +gdk_event_put (GdkEvent *event) +{ + GdkEvent *new_event; + + g_return_if_fail (event != NULL); + + new_event = g_new (GdkEvent, 1); + *new_event = *event; + + 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; + +GdkEvent* +gdk_event_copy (GdkEvent *event) +{ + GdkEvent *new_event; + + g_return_val_if_fail (event != NULL, NULL); + + if (event_chunk == NULL) + event_chunk = g_mem_chunk_new ("events", + sizeof (GdkEvent), + 4096, + G_ALLOC_AND_FREE); + + new_event = g_chunk_new (GdkEvent, event_chunk); + *new_event = *event; + gdk_window_ref (new_event->any.window); + 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); + + gdk_window_unref (event->any.window); + g_mem_chunk_free (event_chunk, event); +} + +/* + *-------------------------------------------------------------- + * gdk_set_debug_level + * + * Sets the debugging level. + * + * Arguments: + * "level" is the new debugging level. + * + * Results: + * + * Side effects: + * Other function calls to "gdk" use the debugging + * level to determine what kind of debugging information + * to print out. + * + *-------------------------------------------------------------- + */ + +void +gdk_set_debug_level (int level) +{ + gdk_debug_level = level; +} + +/* + *-------------------------------------------------------------- + * 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 +gdk_set_show_events (int show_events) +{ + gdk_show_events = show_events; +} + +void +gdk_set_use_xshm (gint use_xshm) +{ + gdk_use_xshm = use_xshm; +} + +gint +gdk_get_debug_level () +{ + return gdk_debug_level; +} + +gint +gdk_get_show_events () +{ + return gdk_show_events; +} + +gint +gdk_get_use_xshm () +{ + 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 +gdk_time_get () +{ + struct timeval end; + struct timeval elapsed; + guint32 milliseconds; + + X_GETTIMEOFDAY (&end); + + 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; + + milliseconds = (elapsed.tv_sec * 1000) + (elapsed.tv_usec / 1000); + + 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 +gdk_timer_get () +{ + 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; + +} + +void +gdk_timer_enable () +{ + timerp = &timer; +} + +void +gdk_timer_disable () +{ + timerp = NULL; +} + +gint +gdk_input_add (gint source, + GdkInputCondition condition, + GdkInputFunction function, + gpointer data) +{ + static gint next_tag = 1; + GList *list; + GdkInput *input; + gint tag; + + tag = 0; + list = inputs; + + while (list) + { + input = list->data; + list = list->next; + + if ((input->source == source) && (input->condition == condition)) + { + input->function = function; + input->data = data; + tag = input->tag; + } + } + + if (!tag) + { + input = g_new (GdkInput, 1); + input->tag = next_tag++; + input->source = source; + input->condition = condition; + input->function = function; + input->data = data; + tag = input->tag; + + inputs = g_list_prepend (inputs, input); + } + + return tag; +} + +void +gdk_input_remove (gint tag) +{ + GList *list; + GList *temp_list; + GdkInput *input; + + list = inputs; + while (list) + { + input = list->data; + + if (input->tag == tag) + { + temp_list = list; + + if (list->next) + list->next->prev = list->prev; + if (list->prev) + list->prev->next = list->next; + if (inputs == list) + inputs = list->next; + + temp_list->next = NULL; + temp_list->prev = NULL; + + g_free (temp_list->data); + g_list_free (temp_list); + break; + } + + list = list->next; + } +} + +/* + *-------------------------------------------------------------- + * gdk_pointer_grab + * + * Grabs the pointer to a specific window + * + * Arguments: + * "window" is the window which will receive the grab + * "owner_events" specifies whether events will be reported as is, + * or relative to "window" + * "event_mask" masks only interesting events + * "confine_to" limits the cursor movement to the specified window + * "cursor" changes the cursor for the duration of the grab + * "time" specifies the time + * + * Results: + * + * Side effects: + * requires a corresponding call to gdk_pointer_ungrab + * + *-------------------------------------------------------------- + */ + +gint +gdk_pointer_grab (GdkWindow * window, + gint owner_events, + GdkEventMask event_mask, + GdkWindow * confine_to, + GdkCursor * cursor, + guint32 time) +{ + /* From gdkwindow.c */ + extern int nevent_masks; + extern int event_mask_table[]; + + gint return_val; + GdkWindowPrivate *window_private; + GdkWindowPrivate *confine_to_private; + GdkCursorPrivate *cursor_private; + guint xevent_mask; + Window xwindow; + Window xconfine_to; + Cursor xcursor; + int i; + + g_return_val_if_fail (window != NULL, 0); + + window_private = (GdkWindowPrivate*) window; + confine_to_private = (GdkWindowPrivate*) confine_to; + cursor_private = (GdkCursorPrivate*) cursor; + + xwindow = window_private->xwindow; + + if (!confine_to) + xconfine_to = None; + else + xconfine_to = confine_to_private->xwindow; + + if (!cursor) + xcursor = None; + else + xcursor = cursor_private->xcursor; + + + xevent_mask = 0; + for (i = 0; i < nevent_masks; i++) + { + if (event_mask & (1 << (i + 1))) + xevent_mask |= event_mask_table[i]; + } + + if (((GdkWindowPrivate *)window)->extension_events && + gdk_input_vtable.grab_pointer) + return_val = gdk_input_vtable.grab_pointer (window, + owner_events, + event_mask, + confine_to, + time); + else + return_val = Success;; + + if (return_val == Success) + return_val = XGrabPointer (window_private->xdisplay, + xwindow, + owner_events, + xevent_mask, + GrabModeAsync, GrabModeAsync, + xconfine_to, + xcursor, + time); + + return return_val; +} + +/* + *-------------------------------------------------------------- + * gdk_pointer_ungrab + * + * Releases any pointer grab + * + * Arguments: + * + * Results: + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +void +gdk_pointer_ungrab (guint32 time) +{ + if (gdk_input_vtable.ungrab_pointer) + gdk_input_vtable.ungrab_pointer (time); + + XUngrabPointer (gdk_display, time); +} + +/* + *-------------------------------------------------------------- + * gdk_keyboard_grab + * + * Grabs the keyboard to a specific window + * + * Arguments: + * "window" is the window which will receive the grab + * "owner_events" specifies whether events will be reported as is, + * or relative to "window" + * "time" specifies the time + * + * Results: + * + * Side effects: + * requires a corresponding call to gdk_keyboard_ungrab + * + *-------------------------------------------------------------- + */ + +gint +gdk_keyboard_grab (GdkWindow * window, + gint owner_events, + guint32 time) +{ + GdkWindowPrivate *window_private; + Window xwindow; + + g_return_val_if_fail (window != NULL, 0); + + window_private = (GdkWindowPrivate*) window; + xwindow = window_private->xwindow; + + return XGrabKeyboard (window_private->xdisplay, + xwindow, + owner_events, + GrabModeAsync, GrabModeAsync, + time); +} + +/* + *-------------------------------------------------------------- + * gdk_keyboard_ungrab + * + * Releases any keyboard grab + * + * Arguments: + * + * Results: + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +void +gdk_keyboard_ungrab (guint32 time) +{ + XUngrabKeyboard (gdk_display, time); +} + +/* + *-------------------------------------------------------------- + * gdk_screen_width + * + * Return the width of the screen. + * + * Arguments: + * + * Results: + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +gint +gdk_screen_width () +{ + gint return_val; + + return_val = DisplayWidth (gdk_display, gdk_screen); + + return return_val; +} + +/* + *-------------------------------------------------------------- + * gdk_screen_height + * + * Return the height of the screen. + * + * Arguments: + * + * Results: + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +gint +gdk_screen_height () +{ + gint return_val; + + return_val = DisplayHeight (gdk_display, gdk_screen); + + return return_val; +} + +void +gdk_key_repeat_disable () +{ + XAutoRepeatOff (gdk_display); +} + +void +gdk_key_repeat_restore () +{ + if (autorepeat) + XAutoRepeatOn (gdk_display); + else + XAutoRepeatOff (gdk_display); +} + + +/* + *-------------------------------------------------------------- + * gdk_flush + * + * Flushes the Xlib output buffer and then waits + * until all requests have been received and processed + * by the X server. The only real use for this function + * is in dealing with XShm. + * + * Arguments: + * + * Results: + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +void gdk_flush () +{ + XSync (gdk_display, False); +} + + +void +gdk_beep () +{ + XBell(gdk_display, 100); +} + + +/* + *-------------------------------------------------------------- + * gdk_event_wait + * + * Waits until an event occurs or the timer runs out. + * + * Arguments: + * + * Results: + * Returns TRUE if an event is ready to be read and FALSE + * if the timer ran out. + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +static gint +gdk_event_wait () +{ + GList *list; + GdkInput *input; + GdkInputCondition condition; + SELECT_MASK readfds; + SELECT_MASK writefds; + SELECT_MASK exceptfds; + int max_input; + int nfd; + + /* If there are no events pending we will wait for an event. + * The time we wait is dependant on the "timer". If no timer + * has been specified then we'll block until an event arrives. + * If a timer has been specified we'll block until an event + * arrives or the timer expires. (This is all done using the + * "select" system call). + */ + + if (XPending (gdk_display) == 0) + { + FD_ZERO (&readfds); + FD_ZERO (&writefds); + FD_ZERO (&exceptfds); + + FD_SET (connection_number, &readfds); + max_input = connection_number; + + list = inputs; + while (list) + { + input = list->data; + list = list->next; + + if (input->condition & GDK_INPUT_READ) + FD_SET (input->source, &readfds); + if (input->condition & GDK_INPUT_WRITE) + FD_SET (input->source, &writefds); + if (input->condition & GDK_INPUT_EXCEPTION) + FD_SET (input->source, &exceptfds); + + max_input = MAX (max_input, input->source); + } + + nfd = select (max_input+1, &readfds, &writefds, &exceptfds, timerp); + + timerp = NULL; + timer_val = 0; + + if (nfd > 0) + { + if (FD_ISSET (connection_number, &readfds)) + { + if (XPending (gdk_display) == 0) + { + if (nfd == 1) + { + XNoOp (gdk_display); + XFlush (gdk_display); + } + return FALSE; + } + else + return TRUE; + } + + list = inputs; + while (list) + { + input = list->data; + list = list->next; + + condition = 0; + if (FD_ISSET (input->source, &readfds)) + condition |= GDK_INPUT_READ; + if (FD_ISSET (input->source, &writefds)) + condition |= GDK_INPUT_WRITE; + if (FD_ISSET (input->source, &exceptfds)) + condition |= GDK_INPUT_EXCEPTION; + + if (condition && input->function) + (* input->function) (input->data, input->source, condition); + } + } + } + else + return TRUE; + + return FALSE; +} + +static gint +gdk_event_translate (GdkEvent *event, + XEvent *xevent) +{ + + GdkWindow *window; + GdkWindowPrivate *window_private; + XComposeStatus compose; + int charcount; + char buf[16]; + gint return_val; + + /* Are static variables used for this purpose thread-safe? */ + static GdkPoint dnd_drag_start = {0,0}, + dnd_drag_oldpos = {0,0}; + static GdkRectangle dnd_drag_dropzone = {0,0,0,0}; + static gint dnd_drag_perhaps = 0; + static GdkWindowPrivate *real_sw = NULL; + static Window dnd_drag_curwin = None, dnd_drag_target = None; + + return_val = FALSE; + + /* Find the GdkWindow that this event occurred in. + * All events occur in some GdkWindow (otherwise, why + * would we be receiving them). It really is an error + * to receive an event for which we cannot find the + * corresponding GdkWindow. We handle events with window=None + * specially - they are generated by XFree86's XInput under + * some circumstances. + */ + + if ((xevent->xany.window == None) && + gdk_input_vtable.window_none_event) + { + return_val = gdk_input_vtable.window_none_event (event,xevent); + + if (return_val >= 0) /* was handled */ + return return_val; + else + return_val = FALSE; + } + + window = gdk_window_lookup (xevent->xany.window); + window_private = (GdkWindowPrivate *) window; + + /* 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. + */ + /* Addendum: + * During drag & drop you get events where the pointer is + * in other windows. Need to just do finer-grained checking + */ + switch (xevent->type) + { + case KeyPress: + /* Lookup the string corresponding to the given keysym. + */ + charcount = XLookupString (&xevent->xkey, buf, 16, + (KeySym*) &event->key.keyval, + &compose); + + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("key press:\t\twindow: %ld key: %12s %d\n", + xevent->xkey.window - base_id, + XKeysymToString (event->key.keyval), + event->key.keyval); + + event->key.type = GDK_KEY_PRESS; + event->key.window = window; + event->key.time = xevent->xkey.time; + event->key.state = (GdkModifierType) xevent->xkey.state; + + return_val = !window_private->destroyed; + break; + + case KeyRelease: + /* Lookup the string corresponding to the given keysym. + */ + charcount = XLookupString (&xevent->xkey, buf, 16, + (KeySym*) &event->key.keyval, + &compose); + + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("key release:\t\twindow: %ld key: %12s %d\n", + xevent->xkey.window - base_id, + 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; + + return_val = !window_private->destroyed; + break; + + case ButtonPress: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("button press[%d]:\t\twindow: %ld x,y: %d %d button: %d\n", + window_private?window_private->dnd_drag_enabled:0, + xevent->xbutton.window - base_id, + xevent->xbutton.x, xevent->xbutton.y, + xevent->xbutton.button); + + if (window_private && + (window_private->extension_events != 0) && + gdk_input_ignore_core) + break; + + event->button.type = GDK_BUTTON_PRESS; + event->button.window = window; + event->button.time = xevent->xbutton.time; + event->button.x = xevent->xbutton.x; + event->button.y = xevent->xbutton.y; + event->button.pressure = 0.5; + event->button.xtilt = 0; + event->button.ytilt = 0; + event->button.state = (GdkModifierType) xevent->xbutton.state; + event->button.button = xevent->xbutton.button; + event->button.source = GDK_SOURCE_MOUSE; + event->button.deviceid = GDK_CORE_POINTER; + + if ((event->button.time < (button_click_time[1] + TRIPLE_CLICK_TIME)) && + (event->button.window == button_window[1]) && + (event->button.button == button_number[1])) + { + 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; + } + else if ((event->button.time < (button_click_time[0] + DOUBLE_CLICK_TIME)) && + (event->button.window == button_window[0]) && + (event->button.button == button_number[0])) + { + 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; + } + else + { + 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; + } + if(window_private + && window_private->dnd_drag_enabled + && !dnd_drag_perhaps + && !gdk_dnd.drag_really) + { + dnd_drag_perhaps = 1; + dnd_drag_start.x = xevent->xbutton.x_root; + dnd_drag_start.y = xevent->xbutton.y_root; + real_sw = window_private; + + if(gdk_dnd.drag_startwindows) + { + g_free(gdk_dnd.drag_startwindows); + gdk_dnd.drag_startwindows = NULL; + } + gdk_dnd.drag_numwindows = gdk_dnd.drag_really = 0; + + { + /* Set motion mask for first DnD'd window, since it + will be the one that is actually dragged */ + XWindowAttributes dnd_winattr; + XSetWindowAttributes dnd_setwinattr; + Status rv; + + /* We need to get motion events while the button is down, so + we can know whether to really start dragging or not... */ + XGetWindowAttributes(gdk_display, (Window)window_private->xwindow, + &dnd_winattr); + + window_private->dnd_drag_savedeventmask = dnd_winattr.your_event_mask; + dnd_setwinattr.event_mask = + window_private->dnd_drag_eventmask = ButtonMotionMask; + XChangeWindowAttributes(gdk_display, window_private->xwindow, + CWEventMask, &dnd_setwinattr); + } + } + return_val = window_private?(!window_private->destroyed):FALSE; + break; + + case ButtonRelease: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("button release[%d]:\twindow: %ld x,y: %d %d button: %d\n", + window_private?window_private->dnd_drag_enabled:0, + xevent->xbutton.window - base_id, + xevent->xbutton.x, xevent->xbutton.y, + xevent->xbutton.button); + + if (window_private && + (window_private->extension_events != 0) && + gdk_input_ignore_core) + break; + + event->button.type = GDK_BUTTON_RELEASE; + event->button.window = window; + event->button.time = xevent->xbutton.time; + event->button.x = xevent->xbutton.x; + event->button.y = xevent->xbutton.y; + event->button.pressure = 0.5; + event->button.xtilt = 0; + event->button.ytilt = 0; + event->button.state = (GdkModifierType) xevent->xbutton.state; + event->button.button = xevent->xbutton.button; + event->button.source = GDK_SOURCE_MOUSE; + event->button.deviceid = GDK_CORE_POINTER; + + if(dnd_drag_perhaps) + { + if(gdk_dnd.drag_really) + { + GdkPoint foo = {xevent->xbutton.x_root, + xevent->xbutton.y_root}; + XUngrabPointer(gdk_display, CurrentTime); + + if(dnd_drag_target != None) + gdk_dnd_drag_end(dnd_drag_target, foo); + gdk_dnd.drag_really = 0; + + if(gdk_dnd.drag_numwindows) + { + XSetWindowAttributes attrs; + /* Reset event mask to pre-drag value, assuming event_mask + doesn't change during drag */ + attrs.event_mask = real_sw->dnd_drag_savedeventmask; + XChangeWindowAttributes(gdk_display, real_sw->xwindow, + CWEventMask, &attrs); + } + + gdk_dnd.drag_numwindows = 0; + if(gdk_dnd.drag_startwindows) + { + g_free(gdk_dnd.drag_startwindows); + gdk_dnd.drag_startwindows = NULL; + } + + real_sw = NULL; + } + + dnd_drag_perhaps = 0; + dnd_drag_start.x = dnd_drag_start.y = 0; + dnd_drag_dropzone.x = dnd_drag_dropzone.y = 0; + dnd_drag_dropzone.width = dnd_drag_dropzone.height = 0; + dnd_drag_curwin = None; + } + return_val = window ? (!window_private->destroyed) : FALSE; + break; + + case MotionNotify: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("motion notify:\t\twindow: %ld x,y: %d %d hint: %s d:%d r%d\n", + xevent->xmotion.window - base_id, + xevent->xmotion.x, xevent->xmotion.y, + (xevent->xmotion.is_hint) ? "true" : "false", + dnd_drag_perhaps, gdk_dnd.drag_really); + + if (window_private && + (window_private->extension_events != 0) && + gdk_input_ignore_core) + break; + + event->motion.type = GDK_MOTION_NOTIFY; + event->motion.window = window; + event->motion.time = xevent->xmotion.time; + event->motion.x = xevent->xmotion.x; + event->motion.y = xevent->xmotion.y; + event->motion.pressure = 0.5; + event->motion.xtilt = 0; + event->motion.ytilt = 0; + event->motion.state = (GdkModifierType) xevent->xmotion.state; + event->motion.is_hint = xevent->xmotion.is_hint; + event->motion.source = GDK_SOURCE_MOUSE; + event->motion.deviceid = GDK_CORE_POINTER; + +#define IS_IN_ZONE(cx, cy) (cx >= dnd_drag_dropzone.x \ + && cy >= dnd_drag_dropzone.y \ + && cx < (dnd_drag_dropzone.x + dnd_drag_dropzone.width) \ + && cy < (dnd_drag_dropzone.y + dnd_drag_dropzone.height)) + + if(dnd_drag_perhaps && gdk_dnd.drag_really) + { + /* First, we have to find what window the motion was in... */ + /* XXX there has to be a better way to do this, perhaps with + XTranslateCoordinates or XQueryTree - I don't know how, + and this sort of works */ + Window curwin, childwin = gdk_root_window, rootwinret; + int x, y; + unsigned int mask; + while(childwin != None) + { + curwin = childwin; + XQueryPointer(gdk_display, curwin, &rootwinret, &childwin, + &x, &y, &x, &y, &mask); + } + if(curwin != dnd_drag_curwin) + { + /* We have left one window and entered another + (do leave & enter bits) */ + if(dnd_drag_curwin != real_sw->xwindow && dnd_drag_curwin != None) + gdk_dnd_drag_leave(dnd_drag_curwin); + dnd_drag_curwin = curwin; + gdk_dnd_drag_enter(dnd_drag_curwin); + dnd_drag_dropzone.x = dnd_drag_dropzone.y = 0; + dnd_drag_dropzone.width = dnd_drag_dropzone.height = 0; + dnd_drag_target = None; + XChangeActivePointerGrab(gdk_display, + ButtonMotionMask | + ButtonPressMask | ButtonReleaseMask | + EnterWindowMask | LeaveWindowMask, + gdk_dnd.gdk_cursor_dragdefault, + CurrentTime); + } + else if(dnd_drag_dropzone.width > 0 + && dnd_drag_dropzone.height > 0) + { + /* Handle all that dropzone stuff - thanks John ;-) */ + if(dnd_drag_target != None + && IS_IN_ZONE(dnd_drag_oldpos.x, dnd_drag_oldpos.y) + && !IS_IN_ZONE(xevent->xmotion.x_root, + xevent->xmotion.y_root)) + { + /* We were in the drop zone and moved out */ + dnd_drag_target = None; + gdk_dnd_drag_leave(curwin); + } + else + { + /* We were outside drop zone but in the window + - have to send enter events */ + gdk_dnd_drag_enter(curwin); + dnd_drag_curwin = curwin; + dnd_drag_dropzone.x = dnd_drag_dropzone.y = 0; + dnd_drag_target = None; + } + } else + dnd_drag_curwin = None; + return_val = FALSE; + } + else + return_val = window?(!window_private->destroyed):FALSE; + break; + + case EnterNotify: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("enter notify:\t\twindow: %ld detail: %d subwin: %ld\n", + xevent->xcrossing.window - base_id, + xevent->xcrossing.detail, + xevent->xcrossing.subwindow - base_id); + + /* Tell XInput stuff about it if appropriate */ + if (window_private && + (window_private->extension_events != 0) && + gdk_input_vtable.enter_event) + gdk_input_vtable.enter_event (&xevent->xcrossing, window); + + 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) + event->crossing.subwindow = gdk_window_lookup (xevent->xcrossing.subwindow); + else + event->crossing.subwindow = NULL; + + /* Translate the crossing detail into Gdk terms. + */ + switch (xevent->xcrossing.detail) + { + case NotifyInferior: + event->crossing.detail = GDK_NOTIFY_INFERIOR; + break; + case NotifyAncestor: + event->crossing.detail = GDK_NOTIFY_ANCESTOR; + break; + case NotifyVirtual: + event->crossing.detail = GDK_NOTIFY_VIRTUAL; + break; + case NotifyNonlinear: + event->crossing.detail = GDK_NOTIFY_NONLINEAR; + break; + case NotifyNonlinearVirtual: + event->crossing.detail = GDK_NOTIFY_NONLINEAR_VIRTUAL; + break; + default: + event->crossing.detail = GDK_NOTIFY_UNKNOWN; + break; + } + + if(dnd_drag_perhaps + && gdk_dnd.drag_really + && xevent->xcrossing.window == real_sw->xwindow) + { + gdk_dnd.drag_really = 0; + XUngrabPointer(gdk_display, CurrentTime); + } + + return_val = (window ? !window_private->destroyed : FALSE); + break; + + case LeaveNotify: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("leave notify:\t\twindow: %ld detail: %d subwin: %ld\n", + xevent->xcrossing.window - base_id, + xevent->xcrossing.detail, xevent->xcrossing.subwindow - base_id); + + event->crossing.type = GDK_LEAVE_NOTIFY; + event->crossing.window = window; + + /* Translate the crossing detail into Gdk terms. + */ + switch (xevent->xcrossing.detail) + { + case NotifyInferior: + event->crossing.detail = GDK_NOTIFY_INFERIOR; + break; + case NotifyAncestor: + event->crossing.detail = GDK_NOTIFY_ANCESTOR; + break; + case NotifyVirtual: + event->crossing.detail = GDK_NOTIFY_VIRTUAL; + break; + case NotifyNonlinear: + event->crossing.detail = GDK_NOTIFY_NONLINEAR; + break; + case NotifyNonlinearVirtual: + event->crossing.detail = GDK_NOTIFY_NONLINEAR_VIRTUAL; + break; + default: + event->crossing.detail = GDK_NOTIFY_UNKNOWN; + break; + } + if(dnd_drag_perhaps + && !gdk_dnd.drag_really) + { + gdk_dnd_drag_addwindow((GdkWindow *) real_sw); + gdk_dnd_drag_begin((GdkWindow *) real_sw); + XGrabPointer(gdk_display, real_sw->xwindow, False, + ButtonMotionMask | + ButtonPressMask | ButtonReleaseMask | + EnterWindowMask | LeaveWindowMask, + GrabModeAsync, GrabModeAsync, gdk_root_window, + gdk_dnd.gdk_cursor_dragdefault, CurrentTime); + gdk_dnd.drag_really = 1; + } + return_val = window ? (!window_private->destroyed) : FALSE; + break; + + case FocusIn: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("focus in:\t\twindow: %ld\n", + xevent->xfocus.window - base_id); + + event->focus_change.type = GDK_FOCUS_CHANGE; + event->focus_change.window = window; + event->focus_change.in = TRUE; + + return_val = !window_private->destroyed; + break; + + case FocusOut: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("focus out:\t\twindow: %ld\n", + xevent->xfocus.window - base_id); + + event->focus_change.type = GDK_FOCUS_CHANGE; + event->focus_change.window = window; + event->focus_change.in = FALSE; + + return_val = !window_private->destroyed; + break; + + case KeymapNotify: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("keymap notify\n"); + + /* Not currently handled */ + break; + + case Expose: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("expose:\t\twindow: %ld %d x,y: %d %d w,h: %d %d\n", + xevent->xexpose.window - base_id, xevent->xexpose.count, + xevent->xexpose.x, xevent->xexpose.y, + xevent->xexpose.width, xevent->xexpose.height); + + event->expose.type = GDK_EXPOSE; + event->expose.window = window; + event->expose.area.x = xevent->xexpose.x; + event->expose.area.y = xevent->xexpose.y; + event->expose.area.width = xevent->xexpose.width; + event->expose.area.height = xevent->xexpose.height; + event->expose.count = xevent->xexpose.count; + + return_val = !window_private->destroyed; + break; + + case GraphicsExpose: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("graphics expose:\tdrawable: %ld\n", + xevent->xgraphicsexpose.drawable - base_id); + + event->expose.type = GDK_EXPOSE; + event->expose.window = window; + event->expose.area.x = xevent->xgraphicsexpose.x; + event->expose.area.y = xevent->xgraphicsexpose.y; + event->expose.area.width = xevent->xgraphicsexpose.width; + event->expose.area.height = xevent->xgraphicsexpose.height; + event->expose.count = xevent->xexpose.count; + + return_val = !window_private->destroyed; + break; + + case NoExpose: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("no expose:\t\tdrawable: %ld\n", + xevent->xnoexpose.drawable - base_id); + + /* Not currently handled */ + break; + + case VisibilityNotify: + /* Print debugging info. + */ + if (gdk_show_events) + switch (xevent->xvisibility.state) + { + case VisibilityFullyObscured: + g_print ("visibility notify:\twindow: %ld none\n", + xevent->xvisibility.window - base_id); + break; + case VisibilityPartiallyObscured: + g_print ("visibility notify:\twindow: %ld partial\n", + xevent->xvisibility.window - base_id); + break; + case VisibilityUnobscured: + g_print ("visibility notify:\twindow: %ld full\n", + xevent->xvisibility.window - base_id); + break; + } + + /* Not currently handled */ + break; + + case CreateNotify: + /* Not currently handled */ + break; + + case DestroyNotify: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("destroy notify:\twindow: %ld\n", + xevent->xdestroywindow.window - base_id); + + event->any.type = GDK_DESTROY; + event->any.window = window; + + /* Remeber which window received the destroy notify + * event so that we can destroy our associated + * data structures the next time the user asks + * us for an event. + */ + received_destroy_notify = TRUE; + window_to_destroy = window; + + return_val = !window_private->destroyed; + break; + + case UnmapNotify: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("unmap notify:\t\twindow: %ld\n", + xevent->xmap.window - base_id); + + event->any.type = GDK_UNMAP; + event->any.window = window; + + return_val = !window_private->destroyed; + break; + + case MapNotify: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("map notify:\t\twindow: %ld\n", + xevent->xmap.window - base_id); + + event->any.type = GDK_MAP; + event->any.window = window; + + return_val = !window_private->destroyed; + break; + + case ReparentNotify: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("reparent notify:\twindow: %ld\n", + xevent->xreparent.window - base_id); + + /* Not currently handled */ + break; + + case ConfigureNotify: + /* Print debugging info. + */ + while ((XPending(gdk_display) > 0) && + XCheckTypedWindowEvent(gdk_display, xevent->xany.window, + ConfigureNotify, xevent)) + /*XSync(gdk_display, 0)*/; + + if (gdk_show_events) + g_print ("configure notify:\twindow: %ld x,y: %d %d w,h: %d %d\n", + xevent->xconfigure.window - base_id, + xevent->xconfigure.x, xevent->xconfigure.y, + xevent->xconfigure.width, xevent->xconfigure.height); + + if (window_private && + (window_private->extension_events != 0) && + gdk_input_vtable.configure_event) + gdk_input_vtable.configure_event (&xevent->xconfigure, window); + + if ((window_private->window_type != GDK_WINDOW_CHILD) && + ((window_private->width != xevent->xconfigure.width) || + (window_private->height != xevent->xconfigure.height))) + { + event->configure.type = GDK_CONFIGURE; + event->configure.window = window; + event->configure.x = xevent->xconfigure.x; + event->configure.y = xevent->xconfigure.y; + event->configure.width = xevent->xconfigure.width; + event->configure.height = xevent->xconfigure.height; + + window_private->x = xevent->xconfigure.x; + window_private->y = xevent->xconfigure.y; + window_private->width = xevent->xconfigure.width; + window_private->height = xevent->xconfigure.height; + if (window_private->resize_count > 1) + window_private->resize_count -= 1; + + return_val = !window_private->destroyed; + } + break; + + case PropertyNotify: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("property notify:\twindow: %ld\n", + xevent->xproperty.window - base_id); + + event->property.type = GDK_PROPERTY_NOTIFY; + event->property.window = window; + event->property.atom = xevent->xproperty.atom; + event->property.time = xevent->xproperty.time; + event->property.state = xevent->xproperty.state; + + return_val = !window_private->destroyed; + break; + + case SelectionClear: + if (gdk_show_events) + g_print ("selection clear:\twindow: %ld\n", + xevent->xproperty.window - base_id); + + event->selection.type = GDK_SELECTION_CLEAR; + event->selection.window = window; + event->selection.selection = xevent->xselectionclear.selection; + event->selection.time = xevent->xselectionclear.time; + + return_val = !((GdkWindowPrivate*) window)->destroyed; + break; + + case SelectionRequest: + if (gdk_show_events) + g_print ("selection request:\twindow: %ld\n", + xevent->xproperty.window - base_id); + + event->selection.type = GDK_SELECTION_REQUEST; + event->selection.window = window; + event->selection.selection = xevent->xselectionrequest.selection; + event->selection.target = xevent->xselectionrequest.target; + event->selection.property = xevent->xselectionrequest.property; + event->selection.requestor = xevent->xselectionrequest.requestor; + event->selection.time = xevent->xselectionrequest.time; + + return_val = !((GdkWindowPrivate*) window)->destroyed; + break; + + case SelectionNotify: + if (gdk_show_events) + g_print ("selection notify:\twindow: %ld\n", + xevent->xproperty.window - base_id); + + + event->selection.type = GDK_SELECTION_NOTIFY; + event->selection.window = window; + event->selection.selection = xevent->xselection.selection; + event->selection.target = xevent->xselection.target; + event->selection.property = xevent->xselection.property; + event->selection.time = xevent->xselection.time; + + return_val = !((GdkWindowPrivate*) window)->destroyed; + break; + + case ColormapNotify: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("colormap notify:\twindow: %ld\n", + xevent->xcolormap.window - base_id); + + /* Not currently handled */ + break; + + case ClientMessage: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("client message:\twindow: %ld\n", + xevent->xclient.window - base_id); + + /* Client messages are the means of the window manager + * communicating with a program. We'll first check to + * see if this is really the window manager talking + * to us. + */ + if (xevent->xclient.message_type == gdk_wm_protocols) + { + if ((Atom) xevent->xclient.data.l[0] == gdk_wm_delete_window) + { + /* The delete window request specifies a window + * to delete. We don't actually destroy the + * window because "it is only a request". (The + * window might contain vital data that the + * program does not want destroyed). Instead + * the event is passed along to the program, + * which should then destroy the window. + */ + + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("delete window:\t\twindow: %ld\n", + xevent->xclient.window - base_id); + + event->any.type = GDK_DELETE; + event->any.window = window; + + return_val = !window_private->destroyed; + } + else if ((Atom) xevent->xclient.data.l[0] == gdk_wm_take_focus) + { + } + } + else if (xevent->xclient.message_type == gdk_dnd.gdk_XdeEnter) + { + Atom reptype = 0; + + event->dropenter.u.allflags = xevent->xclient.data.l[1]; + if (gdk_show_events) + g_print ("GDK_DROP_ENTER\n"); + return_val = FALSE; + + /* Now figure out if we really want this drop... + * If someone is trying funky clipboard stuff, ignore + */ + if (window_private + && window_private->dnd_drop_enabled + && event->dropenter.u.flags.sendreply + && (reptype = gdk_dnd_check_types (window, xevent))) + { + XEvent replyev; + + replyev.xclient.type = ClientMessage; + replyev.xclient.window = xevent->xclient.data.l[0]; + replyev.xclient.format = 32; + replyev.xclient.message_type = gdk_dnd.gdk_XdeRequest; + replyev.xclient.data.l[0] = window_private->xwindow; + + event->dragrequest.u.allflags = 0; + event->dragrequest.u.flags.protocol_version = + DND_PROTOCOL_VERSION; + event->dragrequest.u.flags.willaccept = 1; + event->dragrequest.u.flags.delete_data = + (window_private->dnd_drop_destructive_op) ? 1 : 0; + + replyev.xclient.data.l[1] = event->dragrequest.u.allflags; + replyev.xclient.data.l[2] = replyev.xclient.data.l[3] = 0; + replyev.xclient.data.l[4] = reptype; + + XSendEvent (gdk_display, replyev.xclient.window, + False, NoEventMask, &replyev); + + event->any.type = GDK_DROP_ENTER; + event->dropenter.requestor = replyev.xclient.window; + event->dropenter.u.allflags = xevent->xclient.data.l[1]; + } + } + else if (xevent->xclient.message_type == gdk_dnd.gdk_XdeLeave) + { + if (gdk_show_events) + g_print ("GDK_DROP_LEAVE\n"); + if (window_private && window_private->dnd_drop_enabled) + { + event->dropleave.type = GDK_DROP_LEAVE; + event->dropleave.window = window; + event->dropleave.requestor = xevent->xclient.data.l[0]; + event->dropleave.u.allflags = xevent->xclient.data.l[1]; + return_val = TRUE; + } + else + return_val = FALSE; + } + else if (xevent->xclient.message_type == gdk_dnd.gdk_XdeRequest) + { + /* + * make sure to only handle requests from the window the cursor is + * over + */ + if (gdk_show_events) + g_print ("GDK_DRAG_REQUEST\n"); + event->dragrequest.u.allflags = xevent->xclient.data.l[1]; + return_val = FALSE; + + if (window && gdk_dnd.drag_really && + xevent->xclient.data.l[0] == dnd_drag_curwin && + event->dragrequest.u.flags.sendreply == 0) + { + /* Got request - do we need to ask user? */ + if (!event->dragrequest.u.flags.willaccept + && event->dragrequest.u.flags.senddata) + { + /* Yes we do :) */ + event->dragrequest.type = GDK_DRAG_REQUEST; + event->dragrequest.window = window; + event->dragrequest.requestor = xevent->xclient.data.l[0]; + event->dragrequest.isdrop = 0; + event->dragrequest.drop_coords.x = + event->dragrequest.drop_coords.y = 0; + return_val = TRUE; + } + else if (event->dragrequest.u.flags.willaccept) + { + window_private->dnd_drag_destructive_op = + event->dragrequest.u.flags.delete_data; + window_private->dnd_drag_accepted = 1; + window_private->dnd_drag_data_type = + xevent->xclient.data.l[4]; + + dnd_drag_target = dnd_drag_curwin; + XChangeActivePointerGrab (gdk_display, + ButtonMotionMask | + ButtonPressMask | + ButtonReleaseMask | + EnterWindowMask | LeaveWindowMask, + gdk_dnd.gdk_cursor_dragok, + CurrentTime); + } + dnd_drag_dropzone.x = xevent->xclient.data.l[2] & 65535; + dnd_drag_dropzone.y = + (xevent->xclient.data.l[2] >> 16) & 65535; + dnd_drag_dropzone.width = xevent->xclient.data.l[3] & 65535; + dnd_drag_dropzone.height = + (xevent->xclient.data.l[3] >> 16) & 65535; + } + } + else if(xevent->xclient.message_type == gdk_dnd.gdk_XdeDataAvailable) + { + gint tmp_int; Atom tmp_atom; + gulong tmp_long; + guchar *tmp_charptr; + gpointer tmp_ptr; + + if(gdk_show_events) + g_print("GDK_DROP_DATA_AVAIL\n"); + event->dropdataavailable.u.allflags = xevent->xclient.data.l[1]; + if(window + /* No preview of data ATM */ + && event->dropdataavailable.u.flags.isdrop) + { + event->dropdataavailable.type = GDK_DROP_DATA_AVAIL; + event->dropdataavailable.window = window; + event->dropdataavailable.requestor = xevent->xclient.data.l[0]; + event->dropdataavailable.data_type = + gdk_atom_name(xevent->xclient.data.l[2]); + if(XGetWindowProperty (gdk_display, + event->dropdataavailable.requestor, + xevent->xclient.data.l[2], + 0, LONG_MAX - 1, + False, XA_PRIMARY, &tmp_atom, + &tmp_int, + &event->dropdataavailable.data_numbytes, + &tmp_long, + &tmp_charptr) + != Success) + { + g_warning("XGetWindowProperty on %#x may have failed\n", + event->dropdataavailable.requestor); + event->dropdataavailable.data = NULL; + } + else + { + g_print("XGetWindowProperty got us %d bytes\n", + event->dropdataavailable.data_numbytes); + event->dropdataavailable.data = + g_malloc(event->dropdataavailable.data_numbytes); + memcpy(event->dropdataavailable.data, + tmp_charptr, event->dropdataavailable.data_numbytes); + XFree(tmp_charptr); + return_val = TRUE; + } + return_val = TRUE; + } + } else { + /* Send unknown ClientMessage's on to Gtk for it to use */ + event->client.type = GDK_CLIENT_EVENT; + event->client.window = window; + event->client.message_type = xevent->xclient.message_type; + event->client.data_format = xevent->xclient.format; + memcpy(&event->client.data, &xevent->xclient.data, + sizeof(event->client.data)); + return_val = TRUE; + } + return_val = return_val && !window_private->destroyed; + break; + + case MappingNotify: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("mapping notify\n"); + + /* Let XLib know that there is a new keyboard mapping. + */ + XRefreshKeyboardMapping (&xevent->xmapping); + break; + + default: + /* something else - (e.g., a Xinput event) */ + + if (window_private && + (window_private->extension_events != 0) && + gdk_input_vtable.other_event) + return_val = gdk_input_vtable.other_event(event, xevent, window); + + if (return_val < 0) /* not an XInput event, convert */ + { + event->other.type = GDK_OTHER_EVENT; + event->other.window = window; + event->other.xevent = &other_xevent[other_xevent_i]; + memcpy (&other_xevent[other_xevent_i], xevent, sizeof (XEvent)); + other_xevent_i = (other_xevent_i+1) % OTHER_XEVENT_BUFSIZE; + return_val = TRUE; + } + + return_val = return_val && !window_private->destroyed; + break; + } + + return return_val; +} + +static Bool +gdk_event_get_type (Display *display, + XEvent *xevent, + XPointer arg) +{ + GdkEvent event; + GdkPredicate *pred; + + if (gdk_event_translate (&event, xevent)) + { + pred = (GdkPredicate*) arg; + return (* pred->func) (&event, pred->data); + } + + return FALSE; +} + +static void +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); +} + +/* + *-------------------------------------------------------------- + * gdk_exit_func + * + * This is the "atexit" function that makes sure the + * library gets a chance to cleanup. + * + * Arguments: + * + * Results: + * + * Side effects: + * The library is un-initialized and the program exits. + * + *-------------------------------------------------------------- + */ + +static void +gdk_exit_func () +{ + if (initialized) + { + gdk_image_exit (); + gdk_input_exit (); + gdk_key_repeat_restore (); + + XCloseDisplay (gdk_display); + initialized = 0; + } +} + +/* + *-------------------------------------------------------------- + * gdk_x_error + * + * The X error handling routine. + * + * Arguments: + * "display" is the X display the error orignated from. + * "error" is the XErrorEvent that we are handling. + * + * Results: + * Either we were expecting some sort of error to occur, + * in which case we set the "gdk_error_code" flag, or this + * error was unexpected, in which case we will print an + * error message and exit. (Since trying to continue will + * most likely simply lead to more errors). + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +static int +gdk_x_error (Display *display, + XErrorEvent *error) +{ + char buf[64]; + + if (gdk_error_warnings) + { + XGetErrorText (display, error->error_code, buf, 63); + g_error ("%s", buf); + } + + gdk_error_code = -1; + return 0; +} + +/* + *-------------------------------------------------------------- + * gdk_x_io_error + * + * The X I/O error handling routine. + * + * Arguments: + * "display" is the X display the error orignated from. + * + * Results: + * An X I/O error basically means we lost our connection + * to the X server. There is not much we can do to + * continue, so simply print an error message and exit. + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +static int +gdk_x_io_error (Display *display) +{ + g_error ("an x io error occurred"); + return 0; +} + +/* + *-------------------------------------------------------------- + * gdk_signal + * + * The signal handler. + * + * Arguments: + * "sig_num" is the number of the signal we received. + * + * Results: + * The signals we catch are all fatal. So we simply build + * up a nice little error message and print it and exit. + * If in the process of doing so another signal is received + * we notice that we are already exiting and simply kill + * our process. + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +static RETSIGTYPE +gdk_signal (int sig_num) +{ + static int caught_fatal_sig = 0; + char *sig; + + if (caught_fatal_sig) + kill (getpid (), sig_num); + caught_fatal_sig = 1; + + switch (sig_num) + { + case SIGHUP: + sig = "sighup"; + break; + case SIGINT: + sig = "sigint"; + break; + case SIGQUIT: + sig = "sigquit"; + break; + case SIGBUS: + sig = "sigbus"; + break; + case SIGSEGV: + sig = "sigsegv"; + break; + case SIGPIPE: + sig = "sigpipe"; + break; + case SIGTERM: + sig = "sigterm"; + break; + default: + sig = "unknown signal"; + break; + } + + g_print ("\n** ERROR **: %s caught\n", sig); + gdk_exit (1); +} + +static void +gdk_dnd_drag_begin (GdkWindow *initial_window) +{ + GdkEventDragBegin tev; + tev.type = GDK_DRAG_BEGIN; + tev.window = initial_window; + tev.u.allflags = 0; + tev.u.flags.protocol_version = DND_PROTOCOL_VERSION; + + gdk_event_put ((GdkEvent *) &tev); +} + +static void +gdk_dnd_drag_enter (Window dest) +{ + XEvent sev; + GdkEventDropEnter tev; + int i; + GdkWindowPrivate *wp; + + sev.xclient.type = ClientMessage; + sev.xclient.format = 32; + sev.xclient.message_type = gdk_dnd.gdk_XdeEnter; + sev.xclient.window = dest; + + tev.u.allflags = 0; + tev.u.flags.protocol_version = DND_PROTOCOL_VERSION; + tev.u.flags.sendreply = 1; + for (i = 0; i < gdk_dnd.drag_numwindows; i++) + { + wp = (GdkWindowPrivate *) gdk_dnd.drag_startwindows[i]; + if (wp->dnd_drag_data_numtypesavail) + { + sev.xclient.data.l[0] = wp->xwindow; + tev.u.flags.extended_typelist = (wp->dnd_drag_data_numtypesavail > 3)?1:0; + sev.xclient.data.l[1] = tev.u.allflags; + sev.xclient.data.l[2] = wp->dnd_drag_data_typesavail[0]; + if (wp->dnd_drag_data_numtypesavail > 1) + { + sev.xclient.data.l[3] = wp->dnd_drag_data_typesavail[1]; + if (wp->dnd_drag_data_numtypesavail > 2) + { + sev.xclient.data.l[4] = wp->dnd_drag_data_typesavail[2]; + } + else + sev.xclient.data.l[4] = None; + } + else + sev.xclient.data.l[3] = sev.xclient.data.l[4] = None; + XSendEvent (gdk_display, dest, False, NoEventMask, &sev); + } + + } +} + +static void +gdk_dnd_drag_leave (Window dest) +{ + XEvent sev; + GdkEventDropLeave tev; + int i; + GdkWindowPrivate *wp; + + tev.u.allflags = 0; + + tev.u.flags.protocol_version = DND_PROTOCOL_VERSION; + sev.xclient.type = ClientMessage; + sev.xclient.window = dest; + sev.xclient.format = 32; + sev.xclient.message_type = gdk_dnd.gdk_XdeLeave; + sev.xclient.data.l[1] = tev.u.allflags; + for (i = 0; i < gdk_dnd.drag_numwindows; i++) + { + wp = (GdkWindowPrivate *) gdk_dnd.drag_startwindows[i]; + sev.xclient.data.l[0] = wp->xwindow; + XSendEvent(gdk_display, dest, False, NoEventMask, &sev); + wp->dnd_drag_accepted = 0; + } +} + +/* + * when a drop occurs, we go through the list of windows being dragged and + * tell them that it has occurred, so that they can set things up and reply + * to 'dest' window + */ +static void +gdk_dnd_drag_end (Window dest, + GdkPoint coords) +{ + GdkWindowPrivate *wp; + GdkEventDragRequest tev; + gchar *tmp_cptr; + int i; + + tev.type = GDK_DRAG_REQUEST; + tev.drop_coords = coords; + tev.requestor = dest; + tev.u.allflags = 0; + tev.u.flags.protocol_version = DND_PROTOCOL_VERSION; + tev.isdrop = 1; + + for (i = 0; i < gdk_dnd.drag_numwindows; i++) + { + wp = (GdkWindowPrivate *) gdk_dnd.drag_startwindows[i]; + if (wp->dnd_drag_accepted) + { + tev.window = (GdkWindow *) wp; + tev.u.flags.delete_data = wp->dnd_drag_destructive_op; + tev.data_type = + gdk_atom_name(wp->dnd_drag_data_type); + + gdk_event_put((GdkEvent *) &tev); + } + } +} + +static GdkAtom +gdk_dnd_check_types (GdkWindow *window, + XEvent *xevent) +{ + GdkWindowPrivate *wp = (GdkWindowPrivate *) window; + int i, j; + GdkEventDropEnter event; + + g_return_val_if_fail(window != NULL, 0); + g_return_val_if_fail(xevent != NULL, 0); + g_return_val_if_fail(xevent->type == ClientMessage, 0); + g_return_val_if_fail(xevent->xclient.message_type == gdk_dnd.gdk_XdeEnter, 0); + + if(wp->dnd_drop_data_numtypesavail <= 0 || + !wp->dnd_drop_data_typesavail) + return 0; + + for (i = 2; i <= 4; i++) + { + for (j = 0; j < wp->dnd_drop_data_numtypesavail; j++) + { + if (xevent->xclient.data.l[i] == wp->dnd_drop_data_typesavail[j]) + return xevent->xclient.data.l[i]; + } + } + + /* Now we get the extended type list if it's available */ + event.u.allflags = xevent->xclient.data.l[1]; + if (event.u.flags.extended_typelist) + { + Atom *exttypes, realtype; + gulong nitems, nbar; + gint realfmt; + + if (XGetWindowProperty(gdk_display, xevent->xclient.data.l[0], + gdk_dnd.gdk_XdeTypelist, 0L, LONG_MAX - 1, + False, AnyPropertyType, &realtype, &realfmt, + &nitems, &nbar, (unsigned char **) &exttypes) + != Success) + return 0; + + if (realfmt != (sizeof(Atom) * 8)) + { + g_warning("XdeTypelist property had format of %d instead of the expected %d, on window %#lx\n", + realfmt, sizeof(Atom) * 8, xevent->xclient.data.l[0]); + return 0; + } + + for (i = 0; i <= nitems; i++) + { + for (j = 0; j < wp->dnd_drop_data_numtypesavail; j++) + { + if (exttypes[i] == wp->dnd_drop_data_typesavail[j]) + { + XFree (exttypes); + return exttypes[i]; + } + } + } + XFree (exttypes); + } + return 0; +} + +/* + * used for debugging only + */ +static void +gdk_print_atom (GdkAtom anatom) +{ + gchar *tmpstr = NULL; + tmpstr = (anatom!=None)?gdk_atom_name(anatom):"(none)"; + g_print("Atom %lu has name %s\n", anatom, tmpstr); + if(tmpstr) + g_free(tmpstr); +} + +/* + * used only by below routine and itself + */ +static Window +getchildren (Display *dpy, + Window win, + Atom WM_STATE) +{ + Window root, parent, *children, inf = 0; + Atom type = None; + unsigned int nchildren, i; + int format; + unsigned long nitems, after; + unsigned char *data; + + if (XQueryTree(dpy, win, &root, &parent, &children, &nchildren) == 0) + return 0; + + for (i = 0; !inf && (i < nchildren); i++) + { + XGetWindowProperty (dpy, children[i], WM_STATE, 0, 0, False, + AnyPropertyType, &type, &format, &nitems, + &after, &data); + if (type != 0) + inf = children[i]; + } + + for (i = 0; !inf && (i < nchildren); i++) + inf = getchildren (dpy, children[i], WM_STATE); + + if (children != 0) + XFree ((char *) children); + + return inf; +} + +/* + * find a window with WM_STATE, else return win itself, as per ICCCM + * + * modification of the XmuClientWindow() routine from X11R6.3 + */ +Window +gdk_get_client_window (Display *dpy, + Window win) +{ + Atom WM_STATE; + Atom type = None; + int format; + unsigned long nitems, after; + unsigned char *data; + Window inf; + + if (win == 0) + return DefaultRootWindow(dpy); + + if ((WM_STATE = XInternAtom (dpy, "WM_STATE", True)) == 0) + return win; + + XGetWindowProperty (dpy, win, WM_STATE, 0, 0, False, AnyPropertyType, + &type, &format, &nitems, &after, &data); + if (type) + return win; + + inf = getchildren (dpy, win, WM_STATE); + + if (inf == 0) + return win; + else + return inf; +} + +static GdkWindow * +gdk_drop_get_real_window (GdkWindow *w, + guint16 *x, + guint16 *y) +{ + GdkWindow *retval = w; + GdkWindowPrivate *awin; + GList *children; + gint16 myx = *x, myy = *y; + + g_return_val_if_fail(w != NULL && x != NULL && y != NULL, NULL); + + myx = *x; + myy = *y; + +descend: + for (children = gdk_window_get_children(retval); + children && children->next; + children = children->next) + { + awin = (GdkWindowPrivate *) children->data; + if ((myx >= awin->x) && (myy >= awin->y) + && (myx < (awin->x + awin->width)) + && (myy < (awin->y + awin->height))) + { + retval = (GdkWindow *) awin; + myx -= awin->x; + myy -= awin->y; + goto descend; + } + } + + *x = myx; + *y = myy; + + return retval; +} + +/* Sends a ClientMessage to all toplevel client windows */ +void +gdk_event_send_clientmessage_toall(GdkEvent *event) +{ + XEvent sev; + Window *ret_children, ret_root, ret_parent, curwin; + unsigned int ret_nchildren; + int i; + + g_return_if_fail(event != NULL); + + /* Set up our event to send, with the exception of its target window */ + sev.xclient.type = ClientMessage; + sev.xclient.display = gdk_display; + sev.xclient.format = event->client.data_format; + sev.xclient.serial = CurrentTime; + memcpy(&sev.xclient.data, &event->client.data, sizeof(sev.xclient.data)); + sev.xclient.message_type = event->client.message_type; + + /* OK, we're all set, now let's find some windows to send this to */ + if(XQueryTree(gdk_display, gdk_root_window, &ret_root, &ret_parent, + &ret_children, &ret_nchildren) != True) + return; + + /* foreach true child window of the root window, send an event to it */ + for(i = 0; i < ret_nchildren; i++) { + curwin = gdk_get_client_window(gdk_display, ret_children[i]); + sev.xclient.window = curwin; + XSendEvent(gdk_display, curwin, False, NoEventMask, &sev); + } + + XFree(ret_children); +} diff --git a/gdk/gdk.h b/gdk/gdk.h new file mode 100644 index 000000000..ac341b206 --- /dev/null +++ b/gdk/gdk.h @@ -0,0 +1,614 @@ +/* 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 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef __GDK_H__ +#define __GDK_H__ + + +#include <gdk/gdktypes.h> + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +/* Initialization, exit and events + */ +void gdk_init (int *argc, + char ***argv); +void gdk_exit (int error_code); +gchar* gdk_set_locale (void); + +gint gdk_events_pending (void); +gint gdk_event_get (GdkEvent *event, + GdkEventFunc pred, + gpointer data); +void gdk_event_put (GdkEvent *event); + +GdkEvent *gdk_event_copy (GdkEvent *event); +void gdk_event_free (GdkEvent *event); + +void gdk_set_debug_level (gint level); +void gdk_set_show_events (gint show_events); +void gdk_set_use_xshm (gint use_xshm); + +gint gdk_get_debug_level (void); +gint gdk_get_show_events (void); +gint gdk_get_use_xshm (void); + +guint32 gdk_time_get (void); +guint32 gdk_timer_get (void); +void gdk_timer_set (guint32 milliseconds); +void gdk_timer_enable (void); +void gdk_timer_disable (void); + +gint gdk_input_add (gint source, + GdkInputCondition condition, + GdkInputFunction function, + gpointer data); +void gdk_input_remove (gint tag); + +gint gdk_pointer_grab (GdkWindow * window, + gint owner_events, + GdkEventMask event_mask, + GdkWindow * confine_to, + GdkCursor * cursor, + guint32 time); +void gdk_pointer_ungrab (guint32 time); + +gint gdk_keyboard_grab (GdkWindow * window, + gint owner_events, + guint32 time); +void gdk_keyboard_ungrab (guint32 time); + +gint gdk_screen_width (void); +gint gdk_screen_height (void); + +void gdk_flush (void); +void gdk_beep (void); + +void gdk_key_repeat_disable (void); +void gdk_key_repeat_restore (void); + + +/* Visuals + */ +gint gdk_visual_get_best_depth (void); +GdkVisualType gdk_visual_get_best_type (void); +GdkVisual* gdk_visual_get_system (void); +GdkVisual* gdk_visual_get_best (void); +GdkVisual* gdk_visual_get_best_with_depth (gint depth); +GdkVisual* gdk_visual_get_best_with_type (GdkVisualType visual_type); +GdkVisual* gdk_visual_get_best_with_both (gint depth, + GdkVisualType visual_type); + +/* Actually, these are no-ops... */ +GdkVisual* gdk_visual_ref (GdkVisual *visual); +void gdk_visual_unref (GdkVisual *visual); + +void gdk_query_depths (gint **depths, + gint *count); +void gdk_query_visual_types (GdkVisualType **visual_types, + gint *count); +void gdk_query_visuals (GdkVisual **visuals, + gint *count); + + +/* Windows + */ +GdkWindow* gdk_window_new (GdkWindow *parent, + GdkWindowAttr *attributes, + gint attributes_mask); + +GdkWindow * gdk_window_foreign_new (guint32 anid); +void gdk_window_destroy (GdkWindow *window); +GdkWindow* gdk_window_ref (GdkWindow *window); +void gdk_window_unref (GdkWindow *window); + +void gdk_window_show (GdkWindow *window); +void gdk_window_hide (GdkWindow *window); +void gdk_window_move (GdkWindow *window, + gint x, + gint y); +void gdk_window_resize (GdkWindow *window, + gint width, + gint height); +void gdk_window_move_resize (GdkWindow *window, + gint x, + gint y, + gint width, + gint height); +void gdk_window_reparent (GdkWindow *window, + GdkWindow *new_parent, + gint x, + gint y); +void gdk_window_clear (GdkWindow *window); +void gdk_window_clear_area (GdkWindow *window, + gint x, + gint y, + gint width, + gint height); +void gdk_window_clear_area_e(GdkWindow *window, + gint x, + gint y, + gint width, + gint height); +void gdk_window_copy_area (GdkWindow *window, + GdkGC *gc, + gint x, + gint y, + GdkWindow *source_window, + gint source_x, + gint source_y, + gint width, + gint height); +void gdk_window_raise (GdkWindow *window); +void gdk_window_lower (GdkWindow *window); + +void gdk_window_set_user_data (GdkWindow *window, + gpointer user_data); + + +/* + * This allows for making shaped (partially transparent) windows + * - cool feature, needed for Drag and Drag for example. + * The shape_mask can be the mask + * from gdk_pixmap_create_from_xpm. Stefan Wille + */ +void gdk_window_shape_combine_mask (GdkWindow *window, + GdkBitmap *shape_mask, + gint offset_x, + gint offset_y); + +/* + * Drag & Drop + * Algorithm (drop source): + * A window being dragged will be sent a GDK_DRAG_BEGIN message. + * It will then do gdk_dnd_drag_addwindow() for any other windows that are to be + * dragged. + * When we get a DROP_ENTER incoming, we send it on to the window in question. + * That window needs to use gdk_dnd_drop_enter_reply() to indicate the state of + * things (it must call that even if it's not going to accept the drop) + * + * These two turn on/off drag or drop, and if enabling it also + * sets the list of types supported. The list of types passed in + * should be in order of decreasing preference. + */ +void gdk_window_dnd_drag_set (GdkWindow *window, + guint8 drag_enable, + gchar **typelist, + guint numtypes); + +/* + *XXX todo: add a GDK_DROP_ENTER which can look at actual data + */ +void gdk_window_dnd_drop_set (GdkWindow *window, + guint8 drop_enable, + gchar **typelist, + guint numtypes, + guint8 destructive_op); + +/* + * This is used by the GDK_DRAG_BEGIN handler. An example of usage would be a + * file manager where multiple icons were selected and the drag began. + * The icon that the drag actually began on would gdk_dnd_drag_addwindow + * for all the other icons that were being dragged... + */ +void gdk_dnd_drag_addwindow (GdkWindow *window); +void gdk_window_dnd_data_set (GdkWindow *window, + GdkEvent *event, + gpointer data, + gulong data_numbytes); + + +void gdk_window_set_hints (GdkWindow *window, + gint x, + gint y, + gint min_width, + gint min_height, + gint max_width, + gint max_height, + gint flags); +void gdk_window_set_title (GdkWindow *window, + const gchar *title); +void gdk_window_set_background (GdkWindow *window, + GdkColor *color); +void gdk_window_set_back_pixmap (GdkWindow *window, + GdkPixmap *pixmap, + gint parent_relative); +void gdk_window_set_cursor (GdkWindow *window, + GdkCursor *cursor); +void gdk_window_set_colormap (GdkWindow *window, + GdkColormap *colormap); +void gdk_window_get_user_data (GdkWindow *window, + gpointer *data); +void gdk_window_get_geometry (GdkWindow *window, + gint *x, + gint *y, + gint *width, + gint *height, + gint *depth); +void gdk_window_get_position (GdkWindow *window, + gint *x, + gint *y); +void gdk_window_get_size (GdkWindow *window, + gint *width, + gint *height); +GdkVisual* gdk_window_get_visual (GdkWindow *window); +GdkColormap* gdk_window_get_colormap (GdkWindow *window); +GdkWindowType gdk_window_get_type (GdkWindow *window); +gint gdk_window_get_origin (GdkWindow *window, + gint *x, + gint *y); +GdkWindow* gdk_window_get_pointer (GdkWindow *window, + gint *x, + gint *y, + GdkModifierType *mask); +GdkWindow* gdk_window_get_parent (GdkWindow *window); +GdkWindow* gdk_window_get_toplevel (GdkWindow *window); +GList* gdk_window_get_children (GdkWindow *window); +GdkEventMask gdk_window_get_events (GdkWindow *window); +void gdk_window_set_events (GdkWindow *window, + GdkEventMask event_mask); + +/* Cursors + */ +GdkCursor* gdk_cursor_new (GdkCursorType cursor_type); +void gdk_cursor_destroy (GdkCursor *cursor); + + +/* GCs + */ +GdkGC* gdk_gc_new (GdkWindow *window); +GdkGC* gdk_gc_new_with_values (GdkWindow *window, + GdkGCValues *values, + GdkGCValuesMask values_mask); +void gdk_gc_destroy (GdkGC *gc); +void gdk_gc_get_values (GdkGC *gc, + GdkGCValues *values); +void gdk_gc_set_foreground (GdkGC *gc, + GdkColor *color); +void gdk_gc_set_background (GdkGC *gc, + GdkColor *color); +void gdk_gc_set_font (GdkGC *gc, + GdkFont *font); +void gdk_gc_set_function (GdkGC *gc, + GdkFunction function); +void gdk_gc_set_fill (GdkGC *gc, + GdkFill fill); +void gdk_gc_set_tile (GdkGC *gc, + GdkPixmap *tile); +void gdk_gc_set_stipple (GdkGC *gc, + GdkPixmap *stipple); +void gdk_gc_set_ts_origin (GdkGC *gc, + gint x, + gint y); +void gdk_gc_set_clip_origin (GdkGC *gc, + gint x, + gint y); +void gdk_gc_set_clip_mask (GdkGC *gc, + GdkBitmap *mask); +void gdk_gc_set_clip_rectangle (GdkGC *gc, + GdkRectangle *rectangle); +void gdk_gc_set_subwindow (GdkGC *gc, + GdkSubwindowMode mode); +void gdk_gc_set_exposures (GdkGC *gc, + gint exposures); +void gdk_gc_set_line_attributes (GdkGC *gc, + gint line_width, + GdkLineStyle line_style, + GdkCapStyle cap_style, + GdkJoinStyle join_style); + + +/* Pixmaps + */ +GdkPixmap* gdk_pixmap_new (GdkWindow *window, + gint width, + gint height, + gint depth); +GdkBitmap* gdk_bitmap_create_from_data (GdkWindow *window, + gchar *data, + gint width, + gint height); +GdkPixmap* gdk_pixmap_create_from_data (GdkWindow *window, + gchar *data, + gint width, + gint height, + gint depth, + GdkColor *fg, + GdkColor *bg); +GdkPixmap* gdk_pixmap_create_from_xpm (GdkWindow *window, + GdkBitmap **mask, + GdkColor *transparent_color, + const gchar *filename); +GdkPixmap* gdk_pixmap_create_from_xpm_d (GdkWindow *window, + GdkBitmap **mask, + GdkColor *transparent_color, + gchar **data); +void gdk_pixmap_destroy (GdkPixmap *pixmap); + + + +/* Images + */ +GdkImage* gdk_image_new_bitmap(GdkVisual *, + gpointer, + gint, + gint); +GdkImage* gdk_image_new (GdkImageType type, + GdkVisual *visual, + gint width, + gint height); +GdkImage* gdk_image_get (GdkWindow *window, + gint x, + gint y, + gint width, + gint height); +void gdk_image_put_pixel (GdkImage *image, + gint x, + gint y, + guint32 pixel); +guint32 gdk_image_get_pixel (GdkImage *image, + gint x, + gint y); +void gdk_image_destroy (GdkImage *image); + + +/* Color + */ +GdkColormap* gdk_colormap_new (GdkVisual *visual, + gint allocate); +void gdk_colormap_destroy (GdkColormap *colormap); + +GdkColormap* gdk_colormap_ref (GdkColormap *cmap); +void gdk_colormap_unref (GdkColormap *cmap); + +GdkColormap* gdk_colormap_get_system (void); +gint gdk_colormap_get_system_size (void); + +void gdk_colormap_change (GdkColormap *colormap, + gint ncolors); +void gdk_colors_store (GdkColormap *colormap, + GdkColor *colors, + gint ncolors); +gint gdk_colors_alloc (GdkColormap *colormap, + gint contiguous, + gulong *planes, + gint nplanes, + gulong *pixels, + gint npixels); +void gdk_colors_free (GdkColormap *colormap, + gulong *pixels, + gint npixels, + gulong planes); +gint gdk_color_white (GdkColormap *colormap, + GdkColor *color); +gint gdk_color_black (GdkColormap *colormap, + GdkColor *color); +gint gdk_color_parse (const gchar *spec, + GdkColor *color); +gint gdk_color_alloc (GdkColormap *colormap, + GdkColor *color); +gint gdk_color_change (GdkColormap *colormap, + GdkColor *color); +gint gdk_color_equal (GdkColor *colora, + GdkColor *colorb); + + +/* Fonts + */ +GdkFont* gdk_font_load (const gchar *font_name); +GdkFont* gdk_fontset_load (gchar *fontset_name); +void gdk_font_free (GdkFont *font); +void gdk_fontset_free (GdkFont *font); +GdkFont* gdk_font_ref (GdkFont *font); +gint gdk_font_id (GdkFont *font); +gint gdk_font_equal (GdkFont *fonta, + GdkFont *fontb); +gint gdk_string_width (GdkFont *font, + const gchar *string); +gint gdk_text_width (GdkFont *font, + const gchar *text, + gint text_length); +gint gdk_char_width (GdkFont *font, + gchar character); +gint gdk_string_measure (GdkFont *font, + const gchar *string); +gint gdk_text_measure (GdkFont *font, + const gchar *text, + gint text_length); +gint gdk_char_measure (GdkFont *font, + gchar character); + + +/* Drawing + */ +void gdk_draw_point (GdkDrawable *drawable, + GdkGC *gc, + gint x, + gint y); +void gdk_draw_line (GdkDrawable *drawable, + GdkGC *gc, + gint x1, + gint y1, + gint x2, + gint y2); +void gdk_draw_rectangle (GdkDrawable *drawable, + GdkGC *gc, + gint filled, + gint x, + gint y, + gint width, + gint height); +void gdk_draw_arc (GdkDrawable *drawable, + GdkGC *gc, + gint filled, + gint x, + gint y, + gint width, + gint height, + gint angle1, + gint angle2); +void gdk_draw_polygon (GdkDrawable *drawable, + GdkGC *gc, + gint filled, + GdkPoint *points, + gint npoints); +void gdk_draw_string (GdkDrawable *drawable, + GdkFont *font, + GdkGC *gc, + gint x, + gint y, + const gchar *string); +void gdk_draw_text (GdkDrawable *drawable, + GdkFont *font, + GdkGC *gc, + gint x, + gint y, + const gchar *text, + gint text_length); +void gdk_draw_pixmap (GdkDrawable *drawable, + GdkGC *gc, + GdkDrawable *src, + gint xsrc, + gint ysrc, + gint xdest, + gint ydest, + gint width, + gint height); +void gdk_draw_bitmap (GdkDrawable *drawable, + GdkGC *gc, + GdkDrawable *src, + gint xsrc, + gint ysrc, + gint xdest, + gint ydest, + gint width, + gint height); +void gdk_draw_image (GdkDrawable *drawable, + GdkGC *gc, + GdkImage *image, + gint xsrc, + gint ysrc, + gint xdest, + gint ydest, + gint width, + gint height); +void gdk_draw_points (GdkDrawable *drawable, + GdkGC *gc, + GdkPoint *points, + gint npoints); +void gdk_draw_segments (GdkDrawable *drawable, + GdkGC *gc, + GdkSegment *segs, + gint nsegs); + + +/* Selections + */ +gint gdk_selection_owner_set (GdkWindow *owner, + GdkAtom selection, + guint32 time, + gint send_event); +GdkWindow* gdk_selection_owner_get (GdkAtom selection); +void gdk_selection_convert (GdkWindow *requestor, + GdkAtom selection, + GdkAtom target, + guint32 time); +gint gdk_selection_property_get (GdkWindow *requestor, + guchar **data, + GdkAtom *prop_type, + gint *prop_format); +void gdk_selection_send_notify (guint32 requestor, + GdkAtom selection, + GdkAtom target, + GdkAtom property, + guint32 time); + +/* Properties + */ +GdkAtom gdk_atom_intern (const gchar *atom_name, + gint only_if_exists); +gchar* gdk_atom_name (GdkAtom atom); +gint gdk_property_get (GdkWindow *window, + GdkAtom property, + GdkAtom type, + gulong offset, + gulong length, + gint pdelete, + GdkAtom *actual_property_type, + gint *actual_format, + gint *actual_length, + guchar **data); + +void gdk_property_change (GdkWindow *window, + GdkAtom property, + GdkAtom type, + gint format, + GdkPropMode mode, + guchar *data, + gint nelements); +void gdk_property_delete (GdkWindow *window, + GdkAtom property); + + +/* Rectangle utilities + */ +gint gdk_rectangle_intersect (GdkRectangle *src1, + GdkRectangle *src2, + GdkRectangle *dest); + +/* XInput support + */ + +void gdk_input_init (void); +void gdk_input_exit (void); +GList *gdk_input_list_devices (void); +void gdk_input_set_extension_events (GdkWindow *window, + gint mask, + GdkExtensionMode mode); +void gdk_input_set_source (guint32 deviceid, + GdkInputSource source); +gint gdk_input_set_mode (guint32 deviceid, + GdkInputMode mode); +void gdk_input_set_axes (guint32 deviceid, + GdkAxisUse *axes); +void gdk_input_window_get_pointer (GdkWindow *window, + guint32 deviceid, + gdouble *x, + gdouble *y, + gdouble *pressure, + gdouble *xtilt, + gdouble *ytilt, + GdkModifierType *mask); + +GdkTimeCoord *gdk_input_motion_events (GdkWindow *window, + guint32 deviceid, + guint32 start, + guint32 stop, + gint *nevents_return); + +/* Miscellaneous */ +void gdk_event_send_clientmessage_toall(GdkEvent *event); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GDK_H__ */ diff --git a/gdk/gdkcolor.c b/gdk/gdkcolor.c new file mode 100644 index 000000000..5e66f089b --- /dev/null +++ b/gdk/gdkcolor.c @@ -0,0 +1,718 @@ +/* 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 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include <X11/Xlib.h> +#include "gdk.h" +#include "gdkprivate.h" + + +static gint gdk_colormap_match_color (GdkColormap *cmap, + GdkColor *color, + const gchar *available); +static void gdk_colormap_add (GdkColormap *cmap); +static void gdk_colormap_remove (GdkColormap *cmap); +static guint gdk_colormap_hash (Colormap *cmap); +static gint gdk_colormap_cmp (Colormap *a, + Colormap *b); + +static GHashTable *colormap_hash = NULL; + + +GdkColormap* +gdk_colormap_new (GdkVisual *visual, + gint private_cmap) +{ + GdkColormap *colormap; + GdkColormapPrivate *private; + Visual *xvisual; + XColor default_colors[256]; + int size; + int i; + + g_return_val_if_fail (visual != NULL, NULL); + + private = g_new (GdkColormapPrivate, 1); + colormap = (GdkColormap*) private; + + private->xdisplay = gdk_display; + private->visual = visual; + private->next_color = 0; + private->ref_count = 1; + xvisual = ((GdkVisualPrivate*) visual)->xvisual; + + switch (visual->type) + { + case GDK_VISUAL_GRAYSCALE: + case GDK_VISUAL_PSEUDO_COLOR: + private->private_val = private_cmap; + private->xcolormap = XCreateColormap (private->xdisplay, gdk_root_window, + xvisual, (private_cmap) ? (AllocAll) : (AllocNone)); + + if (private_cmap) + { + for (i = 0; i < 256; i++) + default_colors[i].pixel = i; + + XQueryColors (private->xdisplay, + DefaultColormap (private->xdisplay, gdk_screen), + default_colors, visual->colormap_size); + + for (i = 0; i < visual->colormap_size; i++) + { + colormap->colors[i].pixel = default_colors[i].pixel; + colormap->colors[i].red = default_colors[i].red; + colormap->colors[i].green = default_colors[i].green; + colormap->colors[i].blue = default_colors[i].blue; + } + + gdk_colormap_change (colormap, visual->colormap_size); + } + break; + + case GDK_VISUAL_DIRECT_COLOR: + private->private_val = TRUE; + private->xcolormap = XCreateColormap (private->xdisplay, gdk_root_window, + xvisual, AllocAll); + + size = 1 << visual->red_prec; + for (i = 0; i < size; i++) + colormap->colors[i].red = i * 65535 / (size - 1); + + size = 1 << visual->green_prec; + for (i = 0; i < size; i++) + colormap->colors[i].green = i * 65535 / (size - 1); + + size = 1 << visual->blue_prec; + for (i = 0; i < size; i++) + colormap->colors[i].blue = i * 65535 / (size - 1); + + gdk_colormap_change (colormap, visual->colormap_size); + break; + + case GDK_VISUAL_STATIC_GRAY: + case GDK_VISUAL_STATIC_COLOR: + case GDK_VISUAL_TRUE_COLOR: + private->private_val = FALSE; + private->xcolormap = XCreateColormap (private->xdisplay, gdk_root_window, + xvisual, AllocNone); + break; + } + + gdk_colormap_add (colormap); + + return colormap; +} + +void +gdk_colormap_real_destroy (GdkColormap *colormap) +{ + GdkColormapPrivate *private = (GdkColormapPrivate*) colormap; + + g_return_if_fail (colormap != NULL); + + if (private->ref_count > 0) + return; + + gdk_colormap_remove (colormap); + XFreeColormap (private->xdisplay, private->xcolormap); + g_free (colormap); +} + +void +gdk_colormap_destroy (GdkColormap *colormap) +{ + gdk_colormap_unref (colormap); +} + +GdkColormap* +gdk_colormap_ref (GdkColormap *cmap) +{ + GdkColormapPrivate *private = (GdkColormapPrivate *)cmap; + g_return_val_if_fail (cmap != NULL, NULL); + + private->ref_count += 1; + return cmap; +} + +void +gdk_colormap_unref (GdkColormap *cmap) +{ + GdkColormapPrivate *private = (GdkColormapPrivate *)cmap; + g_return_if_fail (cmap != NULL); + + private->ref_count -= 1; + if (private->ref_count == 0) + gdk_colormap_real_destroy (cmap); +} + +GdkColormap* +gdk_colormap_get_system (void) +{ + static GdkColormap *colormap = NULL; + GdkColormapPrivate *private; + XColor xpalette[256]; + gint i; + + if (!colormap) + { + private = g_new (GdkColormapPrivate, 1); + colormap = (GdkColormap*) private; + + private->xdisplay = gdk_display; + private->xcolormap = DefaultColormap (gdk_display, gdk_screen); + private->visual = gdk_visual_get_system (); + private->private_val = FALSE; + private->next_color = 0; + private->ref_count = 1; + + for (i = 0; i < 256; i++) + { + xpalette[i].pixel = i; + xpalette[i].red = 0; + xpalette[i].green = 0; + xpalette[i].blue = 0; + } + + XQueryColors (gdk_display, private->xcolormap, xpalette, 256); + + for (i = 0; i < 256; i++) + { + colormap->colors[i].pixel = xpalette[i].pixel; + colormap->colors[i].red = xpalette[i].red; + colormap->colors[i].green = xpalette[i].green; + colormap->colors[i].blue = xpalette[i].blue; + } + + gdk_colormap_add (colormap); + } + + return colormap; +} + +gint +gdk_colormap_get_system_size (void) +{ + return DisplayCells (gdk_display, gdk_screen); +} + +void +gdk_colormap_change (GdkColormap *colormap, + gint ncolors) +{ + GdkColormapPrivate *private; + GdkVisual *visual; + XColor palette[256]; + gint shift; + int max_colors; + int size; + int i; + + g_return_if_fail (colormap != NULL); + + private = (GdkColormapPrivate*) colormap; + switch (private->visual->type) + { + case GDK_VISUAL_GRAYSCALE: + case GDK_VISUAL_PSEUDO_COLOR: + for (i = 0; i < ncolors; i++) + { + palette[i].pixel = colormap->colors[i].pixel; + palette[i].red = colormap->colors[i].red; + palette[i].green = colormap->colors[i].green; + palette[i].blue = colormap->colors[i].blue; + palette[i].flags = DoRed | DoGreen | DoBlue; + } + + XStoreColors (private->xdisplay, private->xcolormap, palette, ncolors); + private->next_color = MAX (private->next_color, ncolors); + break; + + case GDK_VISUAL_DIRECT_COLOR: + visual = private->visual; + + shift = visual->red_shift; + max_colors = 1 << visual->red_prec; + size = (ncolors < max_colors) ? (ncolors) : (max_colors); + + for (i = 0; i < size; i++) + { + palette[i].pixel = i << shift; + palette[i].red = colormap->colors[i].red; + palette[i].flags = DoRed; + } + + XStoreColors (private->xdisplay, private->xcolormap, palette, size); + + shift = visual->green_shift; + max_colors = 1 << visual->green_prec; + size = (ncolors < max_colors) ? (ncolors) : (max_colors); + + for (i = 0; i < size; i++) + { + palette[i].pixel = i << shift; + palette[i].green = colormap->colors[i].green; + palette[i].flags = DoGreen; + } + + XStoreColors (private->xdisplay, private->xcolormap, palette, size); + + shift = visual->blue_shift; + max_colors = 1 << visual->blue_prec; + size = (ncolors < max_colors) ? (ncolors) : (max_colors); + + for (i = 0; i < size; i++) + { + palette[i].pixel = i << shift; + palette[i].blue = colormap->colors[i].blue; + palette[i].flags = DoBlue; + } + + XStoreColors (private->xdisplay, private->xcolormap, palette, size); + break; + + default: + break; + } +} + +void +gdk_colors_store (GdkColormap *colormap, + GdkColor *colors, + gint ncolors) +{ + gint i; + + for (i = 0; i < ncolors; i++) + { + colormap->colors[i].pixel = colors[i].pixel; + colormap->colors[i].red = colors[i].red; + colormap->colors[i].green = colors[i].green; + colormap->colors[i].blue = colors[i].blue; + } + + gdk_colormap_change (colormap, ncolors); +} + +gint +gdk_colors_alloc (GdkColormap *colormap, + gint contiguous, + gulong *planes, + gint nplanes, + gulong *pixels, + gint npixels) +{ + GdkColormapPrivate *private; + gint return_val; + + g_return_val_if_fail (colormap != NULL, 0); + + private = (GdkColormapPrivate*) colormap; + + return_val = XAllocColorCells (private->xdisplay, private->xcolormap, + contiguous, planes, nplanes, pixels, npixels); + + return return_val; +} + +void +gdk_colors_free (GdkColormap *colormap, + gulong *pixels, + gint npixels, + gulong planes) +{ + GdkColormapPrivate *private; + + g_return_if_fail (colormap != NULL); + + private = (GdkColormapPrivate*) colormap; + + XFreeColors (private->xdisplay, private->xcolormap, + pixels, npixels, planes); +} + +gint +gdk_color_white (GdkColormap *colormap, + GdkColor *color) +{ + gint return_val; + + g_return_val_if_fail (colormap != NULL, FALSE); + + if (color) + { + color->pixel = WhitePixel (gdk_display, gdk_screen); + color->red = 65535; + color->green = 65535; + color->blue = 65535; + + return_val = gdk_color_alloc (colormap, color); + } + else + return_val = FALSE; + + return return_val; +} + +gint +gdk_color_black (GdkColormap *colormap, + GdkColor *color) +{ + gint return_val; + + g_return_val_if_fail (colormap != NULL, FALSE); + + if (color) + { + color->pixel = BlackPixel (gdk_display, gdk_screen); + color->red = 0; + color->green = 0; + color->blue = 0; + + return_val = gdk_color_alloc (colormap, color); + } + else + return_val = FALSE; + + return return_val; +} + +gint +gdk_color_parse (const gchar *spec, + GdkColor *color) +{ + Colormap xcolormap; + XColor xcolor; + gint return_val; + + g_return_val_if_fail (spec != NULL, FALSE); + g_return_val_if_fail (color != NULL, FALSE); + + xcolormap = DefaultColormap (gdk_display, gdk_screen); + + if (XParseColor (gdk_display, xcolormap, spec, &xcolor)) + { + return_val = TRUE; + color->red = xcolor.red; + color->green = xcolor.green; + color->blue = xcolor.blue; + } + else + return_val = FALSE; + + return return_val; +} + +gint +gdk_color_alloc (GdkColormap *colormap, + GdkColor *color) +{ + GdkColormapPrivate *private; + GdkVisual *visual; + XColor xcolor; + gchar available[256]; + gint available_init; + gint return_val; + gint i, index; + + g_return_val_if_fail (colormap != NULL, FALSE); + g_return_val_if_fail (color != NULL, FALSE); + + xcolor.red = color->red; + xcolor.green = color->green; + xcolor.blue = color->blue; + xcolor.pixel = color->pixel; + xcolor.flags = DoRed | DoGreen | DoBlue; + + return_val = FALSE; + private = (GdkColormapPrivate*) colormap; + + switch (private->visual->type) + { + case GDK_VISUAL_GRAYSCALE: + case GDK_VISUAL_PSEUDO_COLOR: + if (private->private_val) + { + if (private->next_color > 255) + { + for (i = 0; i < 256; i++) + available[i] = TRUE; + + index = gdk_colormap_match_color (colormap, color, available); + if (index != -1) + { + available[index] = FALSE; + *color = colormap->colors[index]; + return_val = TRUE; + } + else + { + return_val = FALSE; + } + } + else + { + xcolor.pixel = 255 - private->next_color; + color->pixel = xcolor.pixel; + private->next_color += 1; + + XStoreColor (private->xdisplay, private->xcolormap, &xcolor); + return_val = TRUE; + } + } + else + { + available_init = 1; + + while (1) + { + if (XAllocColor (private->xdisplay, private->xcolormap, &xcolor)) + { + color->pixel = xcolor.pixel; + color->red = xcolor.red; + color->green = xcolor.green; + color->blue = xcolor.blue; + + colormap->colors[color->pixel] = *color; + + return_val = TRUE; + break; + } + else + { + if (available_init) + { + available_init = 0; + for (i = 0; i < 256; i++) + available[i] = TRUE; + } + + index = gdk_colormap_match_color (colormap, color, available); + if (index != -1) + { + available[index] = FALSE; + xcolor.red = colormap->colors[index].red; + xcolor.green = colormap->colors[index].green; + xcolor.blue = colormap->colors[index].blue; + } + else + { + return_val = FALSE; + break; + } + } + } + } + break; + + case GDK_VISUAL_DIRECT_COLOR: + visual = private->visual; + xcolor.pixel = (((xcolor.red >> (16 - visual->red_prec)) << visual->red_shift) + + ((xcolor.green >> (16 - visual->green_prec)) << visual->green_shift) + + ((xcolor.blue >> (16 - visual->blue_prec)) << visual->blue_shift)); + color->pixel = xcolor.pixel; + return_val = TRUE; + break; + + case GDK_VISUAL_STATIC_GRAY: + case GDK_VISUAL_STATIC_COLOR: + case GDK_VISUAL_TRUE_COLOR: + if (XAllocColor (private->xdisplay, private->xcolormap, &xcolor)) + { + color->pixel = xcolor.pixel; + return_val = TRUE; + } + else + return_val = FALSE; + break; + } + + return return_val; +} + +gint +gdk_color_change (GdkColormap *colormap, + GdkColor *color) +{ + GdkColormapPrivate *private; + XColor xcolor; + + g_return_val_if_fail (colormap != NULL, FALSE); + g_return_val_if_fail (color != NULL, FALSE); + + xcolor.pixel = color->pixel; + xcolor.red = color->red; + xcolor.green = color->green; + xcolor.blue = color->blue; + xcolor.flags = DoRed | DoGreen | DoBlue; + + private = (GdkColormapPrivate*) colormap; + XStoreColor (private->xdisplay, private->xcolormap, &xcolor); + + return TRUE; +} + +gint +gdk_color_equal (GdkColor *colora, + GdkColor *colorb) +{ + g_return_val_if_fail (colora != NULL, FALSE); + g_return_val_if_fail (colorb != NULL, FALSE); + + return ((colora->red == colorb->red) && + (colora->green == colorb->green) && + (colora->blue == colorb->blue)); +} + +GdkColormap* +gdkx_colormap_get (Colormap xcolormap) +{ + GdkColormap *colormap; + GdkColormapPrivate *private; + XColor xpalette[256]; + gint i; + + colormap = gdk_colormap_lookup (xcolormap); + if (colormap) + return colormap; + + if (xcolormap == DefaultColormap (gdk_display, gdk_screen)) + return gdk_colormap_get_system (); + + private = g_new (GdkColormapPrivate, 1); + colormap = (GdkColormap*) private; + + private->xdisplay = gdk_display; + private->xcolormap = xcolormap; + private->visual = NULL; + private->private_val = TRUE; + private->next_color = 0; + + for (i = 0; i < 256; i++) + { + xpalette[i].pixel = i; + xpalette[i].red = 0; + xpalette[i].green = 0; + xpalette[i].blue = 0; + } + + XQueryColors (gdk_display, private->xcolormap, xpalette, 256); + + for (i = 0; i < 256; i++) + { + colormap->colors[i].pixel = xpalette[i].pixel; + colormap->colors[i].red = xpalette[i].red; + colormap->colors[i].green = xpalette[i].green; + colormap->colors[i].blue = xpalette[i].blue; + } + + gdk_colormap_add (colormap); + + return colormap; +} + + +static gint +gdk_colormap_match_color (GdkColormap *cmap, + GdkColor *color, + const gchar *available) +{ + GdkColor *colors; + guint sum, max; + gint rdiff, gdiff, bdiff; + gint i, index; + + g_return_val_if_fail (cmap != NULL, 0); + g_return_val_if_fail (color != NULL, 0); + + colors = cmap->colors; + max = 3 * (65536); + index = -1; + + for (i = 0; i < 256; i++) + { + if ((!available) || (available && available[i])) + { + rdiff = (color->red - colors[i].red); + gdiff = (color->green - colors[i].green); + bdiff = (color->blue - colors[i].blue); + + sum = ABS (rdiff) + ABS (gdiff) + ABS (bdiff); + + if (sum < max) + { + index = i; + max = sum; + } + } + } + + return index; +} + + +GdkColormap* +gdk_colormap_lookup (Colormap xcolormap) +{ + GdkColormap *cmap; + + if (!colormap_hash) + return NULL; + + cmap = g_hash_table_lookup (colormap_hash, &xcolormap); + return cmap; +} + +static void +gdk_colormap_add (GdkColormap *cmap) +{ + GdkColormapPrivate *private; + + if (!colormap_hash) + colormap_hash = g_hash_table_new ((GHashFunc) gdk_colormap_hash, + (GCompareFunc) gdk_colormap_cmp); + + private = (GdkColormapPrivate*) cmap; + + g_hash_table_insert (colormap_hash, &private->xcolormap, cmap); +} + +static void +gdk_colormap_remove (GdkColormap *cmap) +{ + GdkColormapPrivate *private; + + if (!colormap_hash) + colormap_hash = g_hash_table_new ((GHashFunc) gdk_colormap_hash, + (GCompareFunc) gdk_colormap_cmp); + + private = (GdkColormapPrivate*) cmap; + + g_hash_table_remove (colormap_hash, &private->xcolormap); +} + +static guint +gdk_colormap_hash (Colormap *cmap) +{ + return *cmap; +} + +static gint +gdk_colormap_cmp (Colormap *a, + Colormap *b) +{ + return (*a == *b); +} diff --git a/gdk/gdkcursor.c b/gdk/gdkcursor.c new file mode 100644 index 000000000..22bfd250b --- /dev/null +++ b/gdk/gdkcursor.c @@ -0,0 +1,52 @@ +/* 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 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include <X11/Xlib.h> +#include <X11/cursorfont.h> +#include "gdk.h" +#include "gdkprivate.h" + + +GdkCursor* +gdk_cursor_new (GdkCursorType cursor_type) +{ + GdkCursorPrivate *private; + GdkCursor *cursor; + Cursor xcursor; + + xcursor = XCreateFontCursor (gdk_display, cursor_type); + private = g_new (GdkCursorPrivate, 1); + private->xdisplay = gdk_display; + private->xcursor = xcursor; + cursor = (GdkCursor*) private; + cursor->type = cursor_type; + + return cursor; +} + +void +gdk_cursor_destroy (GdkCursor *cursor) +{ + GdkCursorPrivate *private; + + g_return_if_fail (cursor != NULL); + + private = (GdkCursorPrivate *) cursor; + XFreeCursor (private->xdisplay, private->xcursor); + + g_free (private); +} diff --git a/gdk/gdkdraw.c b/gdk/gdkdraw.c new file mode 100644 index 000000000..47482f72e --- /dev/null +++ b/gdk/gdkdraw.c @@ -0,0 +1,383 @@ +/* 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 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include <X11/Xlib.h> +#include <X11/Xos.h> +#include "gdk.h" +#include "gdkprivate.h" + + +void +gdk_draw_point (GdkDrawable *drawable, + GdkGC *gc, + gint x, + gint y) +{ + GdkWindowPrivate *drawable_private; + GdkGCPrivate *gc_private; + + g_return_if_fail (drawable != NULL); + g_return_if_fail (gc != NULL); + + drawable_private = (GdkWindowPrivate*) drawable; + gc_private = (GdkGCPrivate*) gc; + + XDrawPoint (drawable_private->xdisplay, drawable_private->xwindow, + gc_private->xgc, x, y); +} + +void +gdk_draw_line (GdkDrawable *drawable, + GdkGC *gc, + gint x1, + gint y1, + gint x2, + gint y2) +{ + GdkWindowPrivate *drawable_private; + GdkGCPrivate *gc_private; + + g_return_if_fail (drawable != NULL); + g_return_if_fail (gc != NULL); + + drawable_private = (GdkWindowPrivate*) drawable; + gc_private = (GdkGCPrivate*) gc; + + XDrawLine (drawable_private->xdisplay, drawable_private->xwindow, + gc_private->xgc, x1, y1, x2, y2); +} + +void +gdk_draw_rectangle (GdkDrawable *drawable, + GdkGC *gc, + gint filled, + gint x, + gint y, + gint width, + gint height) +{ + GdkWindowPrivate *drawable_private; + GdkGCPrivate *gc_private; + + g_return_if_fail (drawable != NULL); + g_return_if_fail (gc != NULL); + + drawable_private = (GdkWindowPrivate*) drawable; + gc_private = (GdkGCPrivate*) gc; + + if (width == -1) + width = drawable_private->width; + if (height == -1) + height = drawable_private->height; + + if (filled) + XFillRectangle (drawable_private->xdisplay, drawable_private->xwindow, + gc_private->xgc, x, y, width, height); + else + XDrawRectangle (drawable_private->xdisplay, drawable_private->xwindow, + gc_private->xgc, x, y, width, height); +} + +void +gdk_draw_arc (GdkDrawable *drawable, + GdkGC *gc, + gint filled, + gint x, + gint y, + gint width, + gint height, + gint angle1, + gint angle2) +{ + GdkWindowPrivate *drawable_private; + GdkGCPrivate *gc_private; + + g_return_if_fail (drawable != NULL); + g_return_if_fail (gc != NULL); + + drawable_private = (GdkWindowPrivate*) drawable; + gc_private = (GdkGCPrivate*) gc; + + if (width == -1) + width = drawable_private->width; + if (height == -1) + height = drawable_private->height; + + if (filled) + XFillArc (drawable_private->xdisplay, drawable_private->xwindow, + gc_private->xgc, x, y, width, height, angle1, angle2); + else + XDrawArc (drawable_private->xdisplay, drawable_private->xwindow, + gc_private->xgc, x, y, width, height, angle1, angle2); +} + +void +gdk_draw_polygon (GdkDrawable *drawable, + GdkGC *gc, + gint filled, + GdkPoint *points, + gint npoints) +{ + GdkWindowPrivate *drawable_private; + GdkGCPrivate *gc_private; + + g_return_if_fail (drawable != NULL); + g_return_if_fail (gc != NULL); + + drawable_private = (GdkWindowPrivate*) drawable; + gc_private = (GdkGCPrivate*) gc; + + if (filled) + { + XFillPolygon (drawable_private->xdisplay, drawable_private->xwindow, + gc_private->xgc, (XPoint*) points, npoints, Complex, CoordModeOrigin); + } + else + { + XDrawLines (drawable_private->xdisplay, drawable_private->xwindow, + gc_private->xgc, (XPoint*) points, npoints, CoordModeOrigin); + + if ((points[0].x != points[npoints-1].x) || + (points[0].y != points[npoints-1].y)) + XDrawLine (drawable_private->xdisplay, drawable_private->xwindow, + gc_private->xgc, points[npoints-1].x, points[npoints-1].y, + points[0].x, points[0].y); + } +} + +/* gdk_draw_string + * + * Modified by Li-Da Lho to draw 16 bits and Multibyte strings + * + * Interface changed: add "GdkFont *font" to specify font or fontset explicitely + */ +void +gdk_draw_string (GdkDrawable *drawable, + GdkFont *font, + GdkGC *gc, + gint x, + gint y, + const gchar *string) +{ + GdkWindowPrivate *drawable_private; + GdkFontPrivate *font_private; + GdkGCPrivate *gc_private; + + g_return_if_fail (drawable != NULL); + g_return_if_fail (font != NULL); + g_return_if_fail (gc != NULL); + g_return_if_fail (string != NULL); + + drawable_private = (GdkWindowPrivate*) drawable; + gc_private = (GdkGCPrivate*) gc; + font_private = (GdkFontPrivate*) font; + + if (font->type == GDK_FONT_FONT) + { + XFontStruct *xfont = (XFontStruct *) font_private->xfont; + XSetFont(drawable_private->xdisplay, gc_private->xgc, xfont->fid); + if ((xfont->min_byte1 == 0) && (xfont->max_byte1 == 0)) + { + XDrawString (drawable_private->xdisplay, drawable_private->xwindow, + gc_private->xgc, x, y, string, strlen (string)); + } + else + { + XDrawString16 (drawable_private->xdisplay, drawable_private->xwindow, + gc_private->xgc, x, y, (XChar2b *) string, + strlen (string) / 2); + } + } + else if (font->type == GDK_FONT_FONTSET) + { + XFontSet fontset = (XFontSet) font_private->xfont; + XmbDrawString (drawable_private->xdisplay, drawable_private->xwindow, + fontset, gc_private->xgc, x, y, string, strlen (string)); + } + else + g_error("undefined font type\n"); +} + +/* gdk_draw_text + * + * Modified by Li-Da Lho to draw 16 bits and Multibyte strings + * + * Interface changed: add "GdkFont *font" to specify font or fontset explicitely + */ +void +gdk_draw_text (GdkDrawable *drawable, + GdkFont *font, + GdkGC *gc, + gint x, + gint y, + const gchar *text, + gint text_length) +{ + GdkWindowPrivate *drawable_private; + GdkFontPrivate *font_private; + GdkGCPrivate *gc_private; + + g_return_if_fail (drawable != NULL); + g_return_if_fail (font != NULL); + g_return_if_fail (gc != NULL); + g_return_if_fail (text != NULL); + + drawable_private = (GdkWindowPrivate*) drawable; + gc_private = (GdkGCPrivate*) gc; + font_private = (GdkFontPrivate*) font; + + if (font->type == GDK_FONT_FONT) + { + XFontStruct *xfont = (XFontStruct *) font_private->xfont; + XSetFont(drawable_private->xdisplay, gc_private->xgc, xfont->fid); + if ((xfont->min_byte1 == 0) && (xfont->max_byte1 == 0)) + { + XDrawString (drawable_private->xdisplay, drawable_private->xwindow, + gc_private->xgc, x, y, text, text_length); + } + else + { + XDrawString16 (drawable_private->xdisplay, drawable_private->xwindow, + gc_private->xgc, x, y, (XChar2b *) text, text_length / 2); + } + } + else if (font->type == GDK_FONT_FONTSET) + { + XFontSet fontset = (XFontSet) font_private->xfont; + XmbDrawString (drawable_private->xdisplay, drawable_private->xwindow, + fontset, gc_private->xgc, x, y, text, text_length); + } + else + g_error("undefined font type\n"); +} + +void +gdk_draw_pixmap (GdkDrawable *drawable, + GdkGC *gc, + GdkPixmap *src, + gint xsrc, + gint ysrc, + gint xdest, + gint ydest, + gint width, + gint height) +{ + GdkWindowPrivate *drawable_private; + GdkWindowPrivate *src_private; + GdkGCPrivate *gc_private; + + g_return_if_fail (drawable != NULL); + g_return_if_fail (src != NULL); + g_return_if_fail (gc != NULL); + + drawable_private = (GdkWindowPrivate*) drawable; + src_private = (GdkWindowPrivate*) src; + gc_private = (GdkGCPrivate*) gc; + + if (width == -1) + width = src_private->width; + if (height == -1) + height = src_private->height; + + XCopyArea (drawable_private->xdisplay, + src_private->xwindow, + drawable_private->xwindow, + gc_private->xgc, + xsrc, ysrc, + width, height, + xdest, ydest); +} + +void +gdk_draw_image (GdkDrawable *drawable, + GdkGC *gc, + GdkImage *image, + gint xsrc, + gint ysrc, + gint xdest, + gint ydest, + gint width, + gint height) +{ + GdkImagePrivate *image_private; + + g_return_if_fail (drawable != NULL); + g_return_if_fail (image != NULL); + g_return_if_fail (gc != NULL); + + image_private = (GdkImagePrivate*) image; + + g_return_if_fail (image_private->image_put != NULL); + + if (width == -1) + width = image->width; + if (height == -1) + height = image->height; + + (* image_private->image_put) (drawable, gc, image, xsrc, ysrc, + xdest, ydest, width, height); +} + +void +gdk_draw_points (GdkDrawable *drawable, + GdkGC *gc, + GdkPoint *points, + gint npoints) +{ + GdkWindowPrivate *drawable_private; + GdkGCPrivate *gc_private; + + g_return_if_fail (drawable != NULL); + g_return_if_fail ((points != NULL) && (npoints > 0)); + g_return_if_fail (gc != NULL); + + drawable_private = (GdkWindowPrivate*) drawable; + gc_private = (GdkGCPrivate*) gc; + + XDrawPoints (drawable_private->xdisplay, + drawable_private->xwindow, + gc_private->xgc, + (XPoint *) points, + npoints, + CoordModeOrigin); +} + +void +gdk_draw_segments (GdkDrawable *drawable, + GdkGC *gc, + GdkSegment *segs, + gint nsegs) +{ + GdkWindowPrivate *drawable_private; + GdkGCPrivate *gc_private; + + if (nsegs <= 0) + return; + + g_return_if_fail (drawable != NULL); + g_return_if_fail (segs != NULL); + g_return_if_fail (gc != NULL); + + drawable_private = (GdkWindowPrivate*) drawable; + gc_private = (GdkGCPrivate*) gc; + + XDrawSegments (drawable_private->xdisplay, + drawable_private->xwindow, + gc_private->xgc, + (XSegment *) segs, + nsegs); +} diff --git a/gdk/gdkfont.c b/gdk/gdkfont.c new file mode 100644 index 000000000..e1b1e7254 --- /dev/null +++ b/gdk/gdkfont.c @@ -0,0 +1,379 @@ +/* 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 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include <X11/Xlib.h> +#include <X11/Xos.h> +#include "gdk.h" +#include "gdkprivate.h" + +GdkFont* +gdk_font_load (const gchar *font_name) +{ + GdkFont *font; + GdkFontPrivate *private; + + private = g_new (GdkFontPrivate, 1); + font = (GdkFont*) private; + + private->xdisplay = gdk_display; + private->xfont = XLoadQueryFont (private->xdisplay, font_name); + private->ref_count = 1; + + if (!private->xfont) + { + g_free (font); + return NULL; + } + else + { + font->type = GDK_FONT_FONT; + font->ascent = ((XFontStruct *) private->xfont)->ascent; + font->descent = ((XFontStruct *) private->xfont)->descent; + } + + gdk_xid_table_insert (&((XFontStruct *) private->xfont)->fid, font); + + return font; +} + +GdkFont* +gdk_fontset_load(gchar *fontset_name) +{ + GdkFont *font; + GdkFontPrivate *private; + XFontSet fontset; + gint missing_charset_count; + gchar **missing_charset_list; + gchar *def_string; + + private = g_new (GdkFontPrivate, 1); + font = (GdkFont*) private; + + private->xdisplay = gdk_display; + fontset = XCreateFontSet (gdk_display, fontset_name, + &missing_charset_list, &missing_charset_count, + &def_string); + + if (missing_charset_count) + { + g_print ("Missing charsets in FontSet creation"); + XFreeStringList (missing_charset_list); + } + + private->ref_count = 1; + + if (!fontset) + { + g_free (font); + return NULL; + } + else + { + XFontSetExtents *extent = XExtentsOfFontSet(fontset); + + private->xfont = fontset; + font->type = GDK_FONT_FONTSET; + /* how to define ascent and descent for fontset ??? */ + font->ascent = extent->max_logical_extent.height; + font->descent = font->ascent / 4 ; + } + return font; +} +void +gdk_font_free (GdkFont *font) +{ + GdkFontPrivate *private; + + g_return_if_fail (font != NULL); + + private = (GdkFontPrivate*) font; + + private->ref_count -= 1; + if (private->ref_count == 0) + { + gdk_xid_table_remove (((XFontStruct *) private->xfont)->fid); + XFreeFont (private->xdisplay, (XFontStruct *) private->xfont); + g_free (font); + } +} + +void +gdk_fontset_free (GdkFont *font) +{ + GdkFontPrivate *private; + + g_return_if_fail (font != NULL); + + private = (GdkFontPrivate*) font; + + private->ref_count -= 1; + if (private->ref_count == 0) + { + XFreeFontSet (private->xdisplay, (XFontSet) private->xfont); + g_free (font); + } +} + +GdkFont* +gdk_font_ref (GdkFont *font) +{ + GdkFontPrivate *private; + + g_return_val_if_fail (font != NULL, NULL); + + private = (GdkFontPrivate*) font; + private->ref_count += 1; + return font; +} + +gint +gdk_font_id (GdkFont *font) +{ + GdkFontPrivate *font_private; + + g_return_val_if_fail (font != NULL, 0); + + font_private = (GdkFontPrivate*) font; + + if (font->type == GDK_FONT_FONT) + { + return ((XFontStruct *) font_private->xfont)->fid; + } + else + { + return 0; + } +} + +gint +gdk_font_equal (GdkFont *fonta, + GdkFont *fontb) +{ + GdkFontPrivate *privatea; + GdkFontPrivate *privateb; + + g_return_val_if_fail (fonta != NULL, FALSE); + g_return_val_if_fail (fontb != NULL, FALSE); + + privatea = (GdkFontPrivate*) fonta; + privateb = (GdkFontPrivate*) fontb; + + if (fonta->type == GDK_FONT_FONT && fontb->type == GDK_FONT_FONT) + { + return (((XFontStruct *) privatea->xfont)->fid == + ((XFontStruct *) privateb->xfont)->fid); + } + else if (fonta->type == GDK_FONT_FONTSET && fontb->type == GDK_FONT_FONTSET) + { + /* how to compare two fontsets ?? by basename or XFontSet ?? */ + return (((XFontSet) privatea->xfont) == ((XFontSet) privateb->xfont)); + } + else + /* fontset != font */ + return 0; +} + +gint +gdk_string_width (GdkFont *font, + const gchar *string) +{ + GdkFontPrivate *font_private; + gint width; + XFontStruct *xfont; + XFontSet fontset; + + g_return_val_if_fail (font != NULL, -1); + g_return_val_if_fail (string != NULL, -1); + + font_private = (GdkFontPrivate*) font; + + switch (font->type) + { + case GDK_FONT_FONT: + xfont = (XFontStruct *) font_private->xfont; + if ((xfont->min_byte1 == 0) && (xfont->max_byte1 == 0)) + { + width = XTextWidth (xfont, string, strlen (string)); + } + else + { + width = XTextWidth16 (xfont, (XChar2b *) string, strlen (string) / 2); + } + break; + case GDK_FONT_FONTSET: + fontset = (XFontSet) font_private->xfont; + width = XmbTextEscapement (fontset, string, strlen(string)); + break; + default: + width = 0; + } + + return width; +} + +gint +gdk_text_width (GdkFont *font, + const gchar *text, + gint text_length) +{ + GdkFontPrivate *private; + gint width; + XFontStruct *xfont; + XFontSet fontset; + + g_return_val_if_fail (font != NULL, -1); + g_return_val_if_fail (text != NULL, -1); + + private = (GdkFontPrivate*) font; + + switch (font->type) + { + case GDK_FONT_FONT: + xfont = (XFontStruct *) private->xfont; + if ((xfont->min_byte1 == 0) && (xfont->max_byte1 == 0)) + { + width = XTextWidth (xfont, text, text_length); + } + else + { + width = XTextWidth16 (xfont, (XChar2b *) text, text_length / 2); + } + break; + case GDK_FONT_FONTSET: + fontset = (XFontSet) private->xfont; + width = XmbTextEscapement (fontset, text, text_length); + break; + default: + width = 0; + } + return width; +} + +/* Problem: What if a character is a 16 bits character ?? */ +gint +gdk_char_width (GdkFont *font, + gchar character) +{ + GdkFontPrivate *private; + XCharStruct *chars; + gint width; + guint ch = character & 0xff; /* get rid of sign-extension */ + XFontStruct *xfont; + XFontSet fontset; + + g_return_val_if_fail (font != NULL, -1); + + private = (GdkFontPrivate*) font; + + switch (font->type) + { + case GDK_FONT_FONT: + /* only 8 bits characters are considered here */ + xfont = (XFontStruct *) private->xfont; + if ((xfont->min_byte1 == 0) && + (xfont->max_byte1 == 0) && + (ch >= xfont->min_char_or_byte2) && + (ch <= xfont->max_char_or_byte2)) + { + chars = xfont->per_char; + if (chars) + width = chars[ch - xfont->min_char_or_byte2].width; + else + width = xfont->min_bounds.width; + } + else + { + width = XTextWidth (xfont, &character, 1); + } + break; + case GDK_FONT_FONTSET: + fontset = (XFontSet) private->xfont; + width = XmbTextEscapement (fontset, &character, 1) ; + break; + default: + width = 0; + } + return width; +} + +gint +gdk_string_measure (GdkFont *font, + const gchar *string) +{ + g_return_val_if_fail (font != NULL, -1); + g_return_val_if_fail (string != NULL, -1); + + return gdk_text_measure (font, string, strlen (string)); +} + +gint +gdk_text_measure (GdkFont *font, + const gchar *text, + gint text_length) +{ + GdkFontPrivate *private; + XCharStruct overall; + XFontStruct *xfont; + XFontSet fontset; + XRectangle ink, log; + int direction; + int font_ascent; + int font_descent; + gint width; + + g_return_val_if_fail (font != NULL, -1); + g_return_val_if_fail (text != NULL, -1); + + private = (GdkFontPrivate*) font; + + switch (font->type) + { + case GDK_FONT_FONT: + xfont = (XFontStruct *) private->xfont; + if ((xfont->min_byte1 == 0) && (xfont->max_byte1 == 0)) + { + XTextExtents (xfont, text, text_length, + &direction, &font_ascent, &font_descent, + &overall); + } + else + { + XTextExtents16 (xfont, (XChar2b *) text, text_length / 2, + &direction, &font_ascent, &font_descent, + &overall); + } + width = overall.rbearing; + break; + case GDK_FONT_FONTSET: + fontset = (XFontSet) private->xfont; + XmbTextExtents (fontset, text, text_length, &ink, &log); + width = log.width; + break; + default: + width = 0; + } + return width; +} + +gint +gdk_char_measure (GdkFont *font, + gchar character) +{ + g_return_val_if_fail (font != NULL, -1); + + return gdk_text_measure (font, &character, 1); +} diff --git a/gdk/gdkgc.c b/gdk/gdkgc.c new file mode 100644 index 000000000..3dc11ce6c --- /dev/null +++ b/gdk/gdkgc.c @@ -0,0 +1,636 @@ +/* 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 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include <string.h> +#include <X11/Xlib.h> +#include "gdk.h" +#include "gdkprivate.h" + + +GdkGC* +gdk_gc_new (GdkWindow *window) +{ + return gdk_gc_new_with_values (window, NULL, 0); +} + +GdkGC* +gdk_gc_new_with_values (GdkWindow *window, + GdkGCValues *values, + GdkGCValuesMask values_mask) +{ + GdkGC *gc; + GdkGCPrivate *private; + Window xwindow; + XGCValues xvalues; + unsigned long xvalues_mask; + + private = g_new (GdkGCPrivate, 1); + gc = (GdkGC*) private; + + xwindow = ((GdkWindowPrivate*) window)->xwindow; + private->xdisplay = ((GdkWindowPrivate*) window)->xdisplay; + + xvalues.function = GXcopy; + xvalues.fill_style = FillSolid; + xvalues.arc_mode = ArcPieSlice; + xvalues.subwindow_mode = ClipByChildren; + xvalues.graphics_exposures = True; + xvalues_mask = GCFunction | GCFillStyle | GCArcMode | GCSubwindowMode | GCGraphicsExposures; + + if (values_mask & GDK_GC_FOREGROUND) + { + xvalues.foreground = values->foreground.pixel; + xvalues_mask |= GCForeground; + } + if (values_mask & GDK_GC_BACKGROUND) + { + xvalues.background = values->background.pixel; + xvalues_mask |= GCBackground; + } + if ((values_mask & GDK_GC_FONT) && (values->font->type == GDK_FONT_FONT)) + { + xvalues.font = ((XFontStruct *) ((GdkFontPrivate*) values->font)->xfont)->fid; + xvalues_mask |= GCFont; + } + if (values_mask & GDK_GC_FUNCTION) + { + switch (values->function) + { + case GDK_COPY: + xvalues.function = GXcopy; + break; + case GDK_INVERT: + xvalues.function = GXinvert; + break; + case GDK_XOR: + xvalues.function = GXxor; + break; + } + xvalues_mask |= GCFunction; + } + if (values_mask & GDK_GC_FILL) + { + switch (values->fill) + { + case GDK_SOLID: + xvalues.fill_style = FillSolid; + break; + case GDK_TILED: + xvalues.fill_style = FillTiled; + break; + case GDK_STIPPLED: + xvalues.fill_style = FillStippled; + break; + case GDK_OPAQUE_STIPPLED: + xvalues.fill_style = FillOpaqueStippled; + break; + } + xvalues_mask |= GCFillStyle; + } + if (values_mask & GDK_GC_TILE) + { + xvalues.tile = ((GdkPixmapPrivate*) values->tile)->xwindow; + xvalues_mask |= GCTile; + } + if (values_mask & GDK_GC_STIPPLE) + { + xvalues.stipple = ((GdkPixmapPrivate*) values->stipple)->xwindow; + xvalues_mask |= GCStipple; + } + if (values_mask & GDK_GC_CLIP_MASK) + { + xvalues.clip_mask = ((GdkPixmapPrivate*) values->clip_mask)->xwindow; + xvalues_mask |= GCClipMask; + } + if (values_mask & GDK_GC_SUBWINDOW) + { + xvalues.subwindow_mode = values->subwindow_mode; + xvalues_mask |= GCSubwindowMode; + } + if (values_mask & GDK_GC_TS_X_ORIGIN) + { + xvalues.ts_x_origin = values->ts_x_origin; + xvalues_mask |= GCTileStipXOrigin; + } + if (values_mask & GDK_GC_TS_Y_ORIGIN) + { + xvalues.ts_y_origin = values->ts_y_origin; + xvalues_mask |= GCTileStipYOrigin; + } + if (values_mask & GDK_GC_CLIP_X_ORIGIN) + { + xvalues.clip_x_origin = values->clip_x_origin; + xvalues_mask |= GCClipXOrigin; + } + if (values_mask & GDK_GC_CLIP_Y_ORIGIN) + { + xvalues.clip_y_origin = values->clip_y_origin; + xvalues_mask |= GCClipYOrigin; + } + if (values_mask & GDK_GC_EXPOSURES) + { + xvalues.graphics_exposures = values->graphics_exposures; + xvalues_mask |= GCGraphicsExposures; + } + if (values_mask & GDK_GC_LINE_WIDTH) + { + xvalues.line_width = values->line_width; + xvalues_mask |= GCLineWidth; + } + if (values_mask & GDK_GC_LINE_STYLE) + { + switch (values->line_style) + { + case GDK_LINE_SOLID: + xvalues.line_style = LineSolid; + break; + case GDK_LINE_ON_OFF_DASH: + xvalues.line_style = LineOnOffDash; + break; + case GDK_LINE_DOUBLE_DASH: + xvalues.line_style = LineDoubleDash; + break; + } + xvalues_mask |= GCLineStyle; + } + if (values_mask & GDK_GC_CAP_STYLE) + { + switch (values->cap_style) + { + case GDK_CAP_NOT_LAST: + xvalues.cap_style = CapNotLast; + break; + case GDK_CAP_BUTT: + xvalues.cap_style = CapButt; + break; + case GDK_CAP_ROUND: + xvalues.cap_style = CapRound; + break; + case GDK_CAP_PROJECTING: + xvalues.cap_style = CapProjecting; + break; + } + xvalues_mask |= GCCapStyle; + } + if (values_mask & GDK_GC_JOIN_STYLE) + { + switch (values->join_style) + { + case GDK_JOIN_MITER: + xvalues.join_style = JoinMiter; + break; + case GDK_JOIN_ROUND: + xvalues.join_style = JoinRound; + break; + case GDK_JOIN_BEVEL: + xvalues.join_style = JoinBevel; + break; + } + xvalues_mask |= GCJoinStyle; + } + + private->xgc = XCreateGC (private->xdisplay, xwindow, xvalues_mask, &xvalues); + + return gc; +} + +void +gdk_gc_destroy (GdkGC *gc) +{ + GdkGCPrivate *private; + + g_return_if_fail (gc != NULL); + + private = (GdkGCPrivate*) gc; + XFreeGC (private->xdisplay, private->xgc); + + memset (gc, 0, sizeof (GdkGCPrivate)); + g_free (gc); +} + +void +gdk_gc_get_values (GdkGC *gc, + GdkGCValues *values) +{ + GdkGCPrivate *private; + XGCValues xvalues; + + g_return_if_fail (gc != NULL); + g_return_if_fail (values != NULL); + + private = (GdkGCPrivate*) gc; + + if (XGetGCValues (private->xdisplay, private->xgc, + GCForeground | GCBackground | GCFont | + GCFunction | GCTile | GCStipple | /* GCClipMask | */ + GCSubwindowMode | GCGraphicsExposures | + GCTileStipXOrigin | GCTileStipYOrigin | + GCClipXOrigin | GCClipYOrigin | + GCLineWidth | GCLineStyle | GCCapStyle | + GCFillStyle | GCJoinStyle, &xvalues)) + { + values->foreground.pixel = xvalues.foreground; + values->background.pixel = xvalues.background; + values->font = gdk_font_lookup (xvalues.font); + + switch (xvalues.function) + { + case GXcopy: + values->function = GDK_COPY; + break; + case GXinvert: + values->function = GDK_INVERT; + break; + case GXxor: + values->function = GDK_XOR; + break; + } + + switch (xvalues.fill_style) + { + case FillSolid: + values->fill = GDK_SOLID; + break; + case FillTiled: + values->fill = GDK_TILED; + break; + case FillStippled: + values->fill = GDK_STIPPLED; + break; + case FillOpaqueStippled: + values->fill = GDK_OPAQUE_STIPPLED; + break; + } + + values->tile = gdk_pixmap_lookup (xvalues.tile); + values->stipple = gdk_pixmap_lookup (xvalues.stipple); + values->clip_mask = NULL; + values->subwindow_mode = xvalues.subwindow_mode; + values->ts_x_origin = xvalues.ts_x_origin; + values->ts_y_origin = xvalues.ts_y_origin; + values->clip_x_origin = xvalues.clip_x_origin; + values->clip_y_origin = xvalues.clip_y_origin; + values->graphics_exposures = xvalues.graphics_exposures; + values->line_width = xvalues.line_width; + + switch (xvalues.line_style) + { + case LineSolid: + values->line_style = GDK_LINE_SOLID; + break; + case LineOnOffDash: + values->line_style = GDK_LINE_ON_OFF_DASH; + break; + case LineDoubleDash: + values->line_style = GDK_LINE_DOUBLE_DASH; + break; + } + + switch (xvalues.cap_style) + { + case CapNotLast: + values->cap_style = GDK_CAP_NOT_LAST; + break; + case CapButt: + values->cap_style = GDK_CAP_BUTT; + break; + case CapRound: + values->cap_style = GDK_CAP_ROUND; + break; + case CapProjecting: + values->cap_style = GDK_CAP_PROJECTING; + break; + } + + switch (xvalues.join_style) + { + case JoinMiter: + values->join_style = GDK_JOIN_MITER; + break; + case JoinRound: + values->join_style = GDK_JOIN_ROUND; + break; + case JoinBevel: + values->join_style = GDK_JOIN_BEVEL; + break; + } + } + else + { + memset (values, 0, sizeof (GdkGCValues)); + } +} + +void +gdk_gc_set_foreground (GdkGC *gc, + GdkColor *color) +{ + GdkGCPrivate *private; + + g_return_if_fail (gc != NULL); + g_return_if_fail (color != NULL); + + private = (GdkGCPrivate*) gc; + XSetForeground (private->xdisplay, private->xgc, color->pixel); +} + +void +gdk_gc_set_background (GdkGC *gc, + GdkColor *color) +{ + GdkGCPrivate *private; + + g_return_if_fail (gc != NULL); + g_return_if_fail (color != NULL); + + private = (GdkGCPrivate*) gc; + XSetBackground (private->xdisplay, private->xgc, color->pixel); +} + +void +gdk_gc_set_font (GdkGC *gc, + GdkFont *font) +{ + GdkGCPrivate *gc_private; + GdkFontPrivate *font_private; + + g_return_if_fail (gc != NULL); + g_return_if_fail (font != NULL); + + gc_private = (GdkGCPrivate*) gc; + font_private = (GdkFontPrivate*) font; + + XSetFont (gc_private->xdisplay, gc_private->xgc, + ((XFontStruct *) font_private->xfont)->fid); +} + +void +gdk_gc_set_function (GdkGC *gc, + GdkFunction function) +{ + GdkGCPrivate *private; + + g_return_if_fail (gc != NULL); + + private = (GdkGCPrivate*) gc; + + switch (function) + { + case GDK_COPY: + XSetFunction (private->xdisplay, private->xgc, GXcopy); + break; + case GDK_INVERT: + XSetFunction (private->xdisplay, private->xgc, GXinvert); + break; + case GDK_XOR: + XSetFunction (private->xdisplay, private->xgc, GXor); + break; + } +} + +void +gdk_gc_set_fill (GdkGC *gc, + GdkFill fill) +{ + GdkGCPrivate *private; + + g_return_if_fail (gc != NULL); + + private = (GdkGCPrivate*) gc; + + switch (fill) + { + case GDK_SOLID: + XSetFillStyle (private->xdisplay, private->xgc, FillSolid); + break; + case GDK_TILED: + XSetFillStyle (private->xdisplay, private->xgc, FillTiled); + break; + case GDK_STIPPLED: + XSetFillStyle (private->xdisplay, private->xgc, FillStippled); + break; + case GDK_OPAQUE_STIPPLED: + XSetFillStyle (private->xdisplay, private->xgc, FillOpaqueStippled); + break; + } +} + +void +gdk_gc_set_tile (GdkGC *gc, + GdkPixmap *tile) +{ + GdkGCPrivate *private; + GdkPixmapPrivate *pixmap_private; + Pixmap pixmap; + + g_return_if_fail (gc != NULL); + + private = (GdkGCPrivate*) gc; + + pixmap = None; + if (tile) + { + pixmap_private = (GdkPixmapPrivate*) tile; + pixmap = pixmap_private->xwindow; + } + + XSetTile (private->xdisplay, private->xgc, pixmap); +} + +void +gdk_gc_set_stipple (GdkGC *gc, + GdkPixmap *stipple) +{ + GdkGCPrivate *private; + GdkPixmapPrivate *pixmap_private; + Pixmap pixmap; + + g_return_if_fail (gc != NULL); + + private = (GdkGCPrivate*) gc; + + pixmap = None; + if (stipple) + { + pixmap_private = (GdkPixmapPrivate*) stipple; + pixmap = pixmap_private->xwindow; + } + + XSetStipple (private->xdisplay, private->xgc, pixmap); +} + +void +gdk_gc_set_ts_origin (GdkGC *gc, + gint x, + gint y) +{ + GdkGCPrivate *private; + + g_return_if_fail (gc != NULL); + + private = (GdkGCPrivate*) gc; + + XSetTSOrigin (private->xdisplay, private->xgc, x, y); +} + +void +gdk_gc_set_clip_origin (GdkGC *gc, + gint x, + gint y) +{ + GdkGCPrivate *private; + + g_return_if_fail (gc != NULL); + + private = (GdkGCPrivate*) gc; + + XSetClipOrigin (private->xdisplay, private->xgc, x, y); +} + +void +gdk_gc_set_clip_mask (GdkGC *gc, + GdkBitmap *mask) +{ + GdkGCPrivate *private; + Pixmap xmask; + + g_return_if_fail (gc != NULL); + + private = (GdkGCPrivate*) gc; + + if (mask) + xmask = ((GdkWindowPrivate*) mask)->xwindow; + else + xmask = None; + + XSetClipMask (private->xdisplay, private->xgc, xmask); +} + + +void +gdk_gc_set_clip_rectangle (GdkGC *gc, + GdkRectangle *rectangle) +{ + GdkGCPrivate *private; + XRectangle xrectangle; + + g_return_if_fail (gc != NULL); + + private = (GdkGCPrivate*) gc; + + xrectangle.x = rectangle->x; + xrectangle.y = rectangle->y; + xrectangle.width = rectangle->width; + xrectangle.height = rectangle->height; + + XSetClipRectangles (private->xdisplay, private->xgc, 0, 0, + &xrectangle, 1, Unsorted); +} + +void +gdk_gc_set_subwindow (GdkGC *gc, + GdkSubwindowMode mode) +{ + GdkGCPrivate *private; + + g_return_if_fail (gc != NULL); + + private = (GdkGCPrivate*) gc; + + XSetSubwindowMode (private->xdisplay, private->xgc, mode); +} + +void +gdk_gc_set_exposures (GdkGC *gc, + gint exposures) +{ + GdkGCPrivate *private; + + g_return_if_fail (gc != NULL); + + private = (GdkGCPrivate*) gc; + + XSetGraphicsExposures (private->xdisplay, private->xgc, exposures); +} + +void +gdk_gc_set_line_attributes (GdkGC *gc, + gint line_width, + GdkLineStyle line_style, + GdkCapStyle cap_style, + GdkJoinStyle join_style) +{ + GdkGCPrivate *private; + int xline_style; + int xcap_style; + int xjoin_style; + + g_return_if_fail (gc != NULL); + + private = (GdkGCPrivate*) gc; + + switch (line_style) + { + case GDK_LINE_SOLID: + xline_style = LineSolid; + break; + case GDK_LINE_ON_OFF_DASH: + xline_style = LineOnOffDash; + break; + case GDK_LINE_DOUBLE_DASH: + xline_style = LineDoubleDash; + break; + default: + xline_style = None; + } + + switch (cap_style) + { + case GDK_CAP_NOT_LAST: + xcap_style = CapNotLast; + break; + case GDK_CAP_BUTT: + xcap_style = CapButt; + break; + case GDK_CAP_ROUND: + xcap_style = CapRound; + break; + case GDK_CAP_PROJECTING: + xcap_style = CapProjecting; + break; + default: + xcap_style = None; + } + + switch (join_style) + { + case GDK_JOIN_MITER: + xjoin_style = JoinMiter; + break; + case GDK_JOIN_ROUND: + xjoin_style = JoinRound; + break; + case GDK_JOIN_BEVEL: + xjoin_style = JoinBevel; + break; + default: + xjoin_style = None; + } + + XSetLineAttributes (private->xdisplay, private->xgc, line_width, + xline_style, xcap_style, xjoin_style); +} diff --git a/gdk/gdkglobals.c b/gdk/gdkglobals.c new file mode 100644 index 000000000..58f7bf844 --- /dev/null +++ b/gdk/gdkglobals.c @@ -0,0 +1,47 @@ +/* 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 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include <stdio.h> +#include <X11/Xlib.h> +#include "gdktypes.h" +#include "gdkprivate.h" + +gint gdk_debug_level = 0; +gint gdk_show_events = FALSE; +gint gdk_use_xshm = TRUE; +gchar *gdk_display_name = NULL; +Display *gdk_display = NULL; +gint gdk_screen; +Window gdk_root_window; +Window gdk_leader_window; +GdkWindowPrivate gdk_root_parent; +Atom gdk_wm_delete_window; +Atom gdk_wm_take_focus; +Atom gdk_wm_protocols; +Atom gdk_wm_window_protocols[2]; +Atom gdk_selection_property; +GdkDndGlobals gdk_dnd = {None,None,None, + None,None,None, + None, + None,None, + NULL, + 0, 0, + {0,0}}; +gchar *gdk_progname = NULL; +gchar *gdk_progclass = NULL; +gint gdk_error_code; +gint gdk_error_warnings = TRUE; diff --git a/gdk/gdkimage.c b/gdk/gdkimage.c new file mode 100644 index 000000000..bcda3119f --- /dev/null +++ b/gdk/gdkimage.c @@ -0,0 +1,492 @@ +/* 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 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include "../config.h" + +#include <sys/types.h> + +#if defined (HAVE_IPC_H) && defined (HAVE_SHM_H) && defined (HAVE_XSHM_H) +#define USE_SHM +#endif + +#ifdef USE_SHM +#include <sys/ipc.h> +#include <sys/shm.h> +#endif /* USE_SHM */ + +#include <X11/Xlib.h> +#include <X11/Xutil.h> + +#ifdef USE_SHM +#include <X11/extensions/XShm.h> +#endif /* USE_SHM */ + +#include "gdk.h" +#include "gdkprivate.h" + + +static void gdk_image_put_normal (GdkDrawable *drawable, + GdkGC *gc, + GdkImage *image, + gint xsrc, + gint ysrc, + gint xdest, + gint ydest, + gint width, + gint height); +static void gdk_image_put_shared (GdkDrawable *drawable, + GdkGC *gc, + GdkImage *image, + gint xsrc, + gint ysrc, + gint xdest, + gint ydest, + gint width, + gint height); + + +static GList *image_list = NULL; + + +void +gdk_image_exit () +{ + GdkImage *image; + + while (image_list) + { + image = image_list->data; + gdk_image_destroy (image); + } +} + +GdkImage * +gdk_image_new_bitmap(GdkVisual *visual, gpointer data, gint w, gint h) +/* + * Desc: create a new bitmap image + */ +{ + Visual *xvisual; + GdkImage *image; + GdkImagePrivate *private; + private = g_new(GdkImagePrivate, 1); + image = (GdkImage *) private; + private->xdisplay = gdk_display; + private->image_put = gdk_image_put_normal; + image->type = GDK_IMAGE_NORMAL; + image->visual = visual; + image->width = w; + image->height = h; + image->depth = 1; + xvisual = ((GdkVisualPrivate*) visual)->xvisual; + private->ximage = XCreateImage(private->xdisplay, xvisual, 1, XYBitmap, + 0, 0, w ,h, 8, 0); + private->ximage->data = data; + private->ximage->bitmap_bit_order = MSBFirst; + private->ximage->byte_order = MSBFirst; + image->byte_order = MSBFirst; + image->mem = private->ximage->data; + image->bpl = private->ximage->bytes_per_line; + image->bpp = 1; + return(image); +} /* gdk_image_new_bitmap() */ + +static int +gdk_image_check_xshm(Display *display) +/* + * Desc: query the server for support for the MIT_SHM extension + * Return: 0 = not available + * 1 = shared XImage support available + * 2 = shared Pixmap support available also + */ +{ +#ifdef USE_SHM + int major, minor, ignore; + Bool pixmaps; + + if (XQueryExtension(display, "MIT-SHM", &ignore, &ignore, &ignore)) + { + if (XShmQueryVersion(display, &major, &minor, &pixmaps )==True) + { + return (pixmaps==True) ? 2 : 1; + } + } +#endif /* USE_SHM */ + return 0; +} + +void +gdk_image_init () +{ + if (gdk_use_xshm) + { + if (!gdk_image_check_xshm (gdk_display)) + { + g_warning ("MIT-SHM Extension not availible on server"); + gdk_use_xshm = False; + } + } +} + +GdkImage* +gdk_image_new (GdkImageType type, + GdkVisual *visual, + gint width, + gint height) +{ + GdkImage *image; + GdkImagePrivate *private; +#ifdef USE_SHM + XShmSegmentInfo *x_shm_info; +#endif /* USE_SHM */ + Visual *xvisual; + + switch (type) + { + case GDK_IMAGE_FASTEST: + image = gdk_image_new (GDK_IMAGE_SHARED, visual, width, height); + + if (!image) + image = gdk_image_new (GDK_IMAGE_NORMAL, visual, width, height); + break; + + default: + private = g_new (GdkImagePrivate, 1); + image = (GdkImage*) private; + + private->xdisplay = gdk_display; + private->image_put = NULL; + + image->type = type; + image->visual = visual; + image->width = width; + image->height = height; + image->depth = visual->depth; + + xvisual = ((GdkVisualPrivate*) visual)->xvisual; + + switch (type) + { + case GDK_IMAGE_SHARED: +#ifdef USE_SHM + if (gdk_use_xshm) + { + private->image_put = gdk_image_put_shared; + + private->x_shm_info = g_new (XShmSegmentInfo, 1); + x_shm_info = private->x_shm_info; + + private->ximage = XShmCreateImage (private->xdisplay, xvisual, visual->depth, + ZPixmap, NULL, x_shm_info, width, height); + if (private->ximage == NULL) + { + g_warning ("XShmCreateImage failed"); + + g_free (image); + gdk_use_xshm = False; + return NULL; + } + + x_shm_info->shmid = shmget (IPC_PRIVATE, + private->ximage->bytes_per_line * private->ximage->height, + IPC_CREAT | 0777); + + if (x_shm_info->shmid == -1) + { + g_warning ("shmget failed!"); + + XDestroyImage (private->ximage); + g_free (private->x_shm_info); + g_free (image); + + gdk_use_xshm = False; + gdk_use_xshm = False; + return NULL; + } + + x_shm_info->readOnly = False; + x_shm_info->shmaddr = shmat (x_shm_info->shmid, 0, 0); + private->ximage->data = x_shm_info->shmaddr; + + if (x_shm_info->shmaddr == (char*) -1) + { + g_warning ("shmat failed!"); + + XDestroyImage (private->ximage); + shmctl (x_shm_info->shmid, IPC_RMID, 0); + + g_free (private->x_shm_info); + g_free (image); + + return NULL; + } + +#ifdef IPC_RMID_DEFERRED_RELEASE + if (x_shm_info->shmaddr != (char*) -1) + shmctl (x_shm_info->shmid, IPC_RMID, 0); +#endif + + gdk_error_code = 0; + gdk_error_warnings = 0; + + XShmAttach (private->xdisplay, x_shm_info); + XSync (private->xdisplay, False); + + gdk_error_warnings = 1; + if (gdk_error_code == -1) + { + g_warning ("XShmAttach failed!"); + + XDestroyImage (private->ximage); + shmdt (x_shm_info->shmaddr); + shmctl (x_shm_info->shmid, IPC_RMID, 0); + + g_free (private->x_shm_info); + g_free (image); + + gdk_use_xshm = False; + return NULL; + } + + if (image) + image_list = g_list_prepend (image_list, image); + } + else + { + g_free (image); + return NULL; + } + break; +#else /* USE_SHM */ + g_free (image); + return NULL; +#endif /* USE_SHM */ + case GDK_IMAGE_NORMAL: + private->image_put = gdk_image_put_normal; + + private->ximage = XCreateImage (private->xdisplay, xvisual, visual->depth, + ZPixmap, 0, 0, width, height, 32, 0); + + private->ximage->data = g_new (char, private->ximage->bytes_per_line * + private->ximage->height); + break; + + case GDK_IMAGE_FASTEST: + g_assert_not_reached (); + } + + if (image) + { + image->byte_order = private->ximage->byte_order; + image->mem = private->ximage->data; + image->bpl = private->ximage->bytes_per_line; + + switch (private->ximage->bits_per_pixel) + { + case 8: + image->bpp = 1; + break; + case 16: + image->bpp = 2; + break; + case 24: + image->bpp = 3; + break; + case 32: + image->bpp = 4; + break; + } + } + } + + return image; +} + +GdkImage* +gdk_image_get (GdkWindow *window, + gint x, + gint y, + gint width, + gint height) +{ + GdkImage *image; + GdkImagePrivate *private; + GdkWindowPrivate *win_private; + + g_return_val_if_fail (window != NULL, NULL); + + win_private = (GdkWindowPrivate *) window; + + private = g_new (GdkImagePrivate, 1); + image = (GdkImage*) private; + + private->xdisplay = gdk_display; + private->image_put = gdk_image_put_normal; + private->ximage = XGetImage (private->xdisplay, + win_private->xwindow, + x, y, width, height, + AllPlanes, ZPixmap); + + image->type = GDK_IMAGE_NORMAL; + image->visual = gdk_window_get_visual (window); + image->width = width; + image->height = height; + image->depth = private->ximage->depth; + + image->mem = private->ximage->data; + image->bpl = private->ximage->bytes_per_line; + image->bpp = 1; + + return image; +} + +guint32 +gdk_image_get_pixel (GdkImage *image, + gint x, + gint y) +{ + guint32 pixel; + GdkImagePrivate *private; + + g_return_val_if_fail (image != NULL, 0); + + private = (GdkImagePrivate *) image; + + pixel = XGetPixel (private->ximage, x, y); + + return pixel; +} + +void +gdk_image_put_pixel (GdkImage *image, + gint x, + gint y, + guint32 pixel) +{ + GdkImagePrivate *private; + + g_return_if_fail (image != NULL); + + private = (GdkImagePrivate *) image; + + pixel = XPutPixel (private->ximage, x, y, pixel); +} + +void +gdk_image_destroy (GdkImage *image) +{ + GdkImagePrivate *private; +#ifdef USE_SHM + XShmSegmentInfo *x_shm_info; +#endif /* USE_SHM */ + + g_return_if_fail (image != NULL); + + private = (GdkImagePrivate*) image; + switch (image->type) + { + case GDK_IMAGE_NORMAL: + XDestroyImage (private->ximage); + break; + + case GDK_IMAGE_SHARED: +#ifdef USE_SHM + XShmDetach (private->xdisplay, private->x_shm_info); + XDestroyImage (private->ximage); + + x_shm_info = private->x_shm_info; + shmdt (x_shm_info->shmaddr); + shmctl (x_shm_info->shmid, IPC_RMID, 0); + + g_free (private->x_shm_info); + + image_list = g_list_remove (image_list, image); +#else /* USE_SHM */ + g_error ("trying to destroy shared memory image when gdk was compiled without shared memory support"); +#endif /* USE_SHM */ + break; + + case GDK_IMAGE_FASTEST: + g_assert_not_reached (); + } + + g_free (image); +} + +static void +gdk_image_put_normal (GdkDrawable *drawable, + GdkGC *gc, + GdkImage *image, + gint xsrc, + gint ysrc, + gint xdest, + gint ydest, + gint width, + gint height) +{ + GdkWindowPrivate *drawable_private; + GdkImagePrivate *image_private; + GdkGCPrivate *gc_private; + + g_return_if_fail (drawable != NULL); + g_return_if_fail (image != NULL); + g_return_if_fail (gc != NULL); + + drawable_private = (GdkWindowPrivate*) drawable; + image_private = (GdkImagePrivate*) image; + gc_private = (GdkGCPrivate*) gc; + + g_return_if_fail (image->type == GDK_IMAGE_NORMAL); + + XPutImage (drawable_private->xdisplay, drawable_private->xwindow, + gc_private->xgc, image_private->ximage, + xsrc, ysrc, xdest, ydest, width, height); +} + +static void +gdk_image_put_shared (GdkDrawable *drawable, + GdkGC *gc, + GdkImage *image, + gint xsrc, + gint ysrc, + gint xdest, + gint ydest, + gint width, + gint height) +{ +#ifdef USE_SHM + GdkWindowPrivate *drawable_private; + GdkImagePrivate *image_private; + GdkGCPrivate *gc_private; + + g_return_if_fail (drawable != NULL); + g_return_if_fail (image != NULL); + g_return_if_fail (gc != NULL); + + drawable_private = (GdkWindowPrivate*) drawable; + image_private = (GdkImagePrivate*) image; + gc_private = (GdkGCPrivate*) gc; + + g_return_if_fail (image->type == GDK_IMAGE_SHARED); + + XShmPutImage (drawable_private->xdisplay, drawable_private->xwindow, + gc_private->xgc, image_private->ximage, + xsrc, ysrc, xdest, ydest, width, height, False); +#else /* USE_SHM */ + g_error ("trying to draw shared memory image when gdk was compiled without shared memory support"); +#endif /* USE_SHM */ +} diff --git a/gdk/gdkinput.c b/gdk/gdkinput.c new file mode 100644 index 000000000..ad4b1fcc9 --- /dev/null +++ b/gdk/gdkinput.c @@ -0,0 +1,324 @@ +/* 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 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include <stdlib.h> +#include <X11/Xlib.h> +#include <X11/Xutil.h> +#include "../config.h" +#include "gdk.h" +#include "gdkx.h" +#include "gdkprivate.h" +#include "gdkinput.h" + + +/* Forward declarations */ + +static gint gdk_input_enable_window (GdkWindow *window, + GdkDevicePrivate *gdkdev); +static gint gdk_input_disable_window (GdkWindow *window, + GdkDevicePrivate *gdkdev); +static GdkInputWindow *gdk_input_window_find (GdkWindow *window); +static GdkDevicePrivate *gdk_input_find_device (guint32 id); + + +/* Incorporate the specific routines depending on compilation options */ + +static GdkAxisUse gdk_input_core_axes[] = { GDK_AXIS_X, GDK_AXIS_Y }; + +static GdkDeviceInfo gdk_input_core_info = +{ + GDK_CORE_POINTER, + "Core Pointer", + GDK_SOURCE_MOUSE, + GDK_MODE_SCREEN, + TRUE, + 2, + gdk_input_core_axes +}; + +/* Global variables */ + +GdkInputVTable gdk_input_vtable; +/* information about network port and host for gxid daemon */ +gchar *gdk_input_gxid_host; +gint gdk_input_gxid_port; +gint gdk_input_ignore_core; + +/* Local variables */ + +static GList *gdk_input_devices; +static GList *gdk_input_windows; + +#include "gdkinputnone.h" +#include "gdkinputcommon.h" +#include "gdkinputxfree.h" +#include "gdkinputgxi.h" + +GList * +gdk_input_list_devices () +{ + return gdk_input_devices; +} + +void +gdk_input_set_source (guint32 deviceid, GdkInputSource source) +{ + GdkDevicePrivate *gdkdev = gdk_input_find_device(deviceid); + g_return_if_fail (gdkdev != NULL); + + gdkdev->info.source = source; +} + +gint +gdk_input_set_mode (guint32 deviceid, GdkInputMode mode) +{ + if (deviceid == GDK_CORE_POINTER) + return FALSE; + + if (gdk_input_vtable.set_mode) + return gdk_input_vtable.set_mode(deviceid,mode); + else + return FALSE; +} + +void +gdk_input_set_axes (guint32 deviceid, GdkAxisUse *axes) +{ + if (deviceid != GDK_CORE_POINTER && gdk_input_vtable.set_axes) + gdk_input_vtable.set_axes (deviceid, axes); +} + +GdkTimeCoord * +gdk_input_motion_events (GdkWindow *window, + guint32 deviceid, + guint32 start, + guint32 stop, + gint *nevents_return) +{ + XTimeCoord *xcoords; + GdkTimeCoord *coords; + int i; + + if (deviceid == GDK_CORE_POINTER) + { + xcoords = XGetMotionEvents (gdk_display, + ((GdkWindowPrivate *)window)->xwindow, + start, stop, nevents_return); + if (xcoords) + { + coords = g_new (GdkTimeCoord, *nevents_return); + for (i=0; i<*nevents_return; i++) + { + coords[i].time = xcoords[i].time; + coords[i].x = xcoords[i].x; + coords[i].y = xcoords[i].y; + coords[i].pressure = 0.5; + coords[i].xtilt = 0.0; + coords[i].ytilt = 0.0; + } + + XFree(xcoords); + + return coords; + } + else + return NULL; + } + else + { + if (gdk_input_vtable.motion_events) + { + return gdk_input_vtable.motion_events(window, + deviceid, start, stop, + nevents_return); + } + else + { + *nevents_return = 0; + return NULL; + } + } +} + +static gint +gdk_input_enable_window (GdkWindow *window, GdkDevicePrivate *gdkdev) +{ + if (gdk_input_vtable.enable_window) + return gdk_input_vtable.enable_window (window, gdkdev); + else + return TRUE; +} + +static gint +gdk_input_disable_window (GdkWindow *window, GdkDevicePrivate *gdkdev) +{ + if (gdk_input_vtable.disable_window) + return gdk_input_vtable.disable_window(window,gdkdev); + else + return TRUE; +} + + +static GdkInputWindow * +gdk_input_window_find(GdkWindow *window) +{ + GList *tmp_list; + + for (tmp_list=gdk_input_windows; tmp_list; tmp_list=tmp_list->next) + if (((GdkInputWindow *)(tmp_list->data))->window == window) + return (GdkInputWindow *)(tmp_list->data); + + return NULL; /* Not found */ +} + +/* FIXME: this routine currently needs to be called between creation + and the corresponding configure event (because it doesn't get the + root_relative_geometry). This should work with + gtk_window_set_extension_events, but will likely fail in other + cases */ + +void +gdk_input_set_extension_events (GdkWindow *window, gint mask, + GdkExtensionMode mode) +{ + GList *tmp_list; + GdkInputWindow *iw; + + g_return_if_fail (window != NULL); + + if (mode == GDK_EXTENSION_EVENTS_NONE) + mask = 0; + + if (mask != 0) + { + iw = g_new(GdkInputWindow,1); + + iw->window = window; + iw->mode = mode; + + iw->obscuring = NULL; + iw->num_obscuring = 0; + iw->grabbed = FALSE; + + gdk_input_windows = g_list_append(gdk_input_windows,iw); + ((GdkWindowPrivate *)window)->extension_events = mask; + + /* Add enter window events to the event mask */ + /* FIXME, this is not needed for XINPUT_NONE */ + gdk_window_set_events (window, + gdk_window_get_events (window) | + GDK_ENTER_NOTIFY_MASK); + } + else + { + iw = gdk_input_window_find (window); + if (iw) + { + gdk_input_windows = g_list_remove(gdk_input_windows,iw); + g_free(iw); + } + + ((GdkWindowPrivate *)window)->extension_events = 0; + } + + for (tmp_list = gdk_input_devices; tmp_list; tmp_list = tmp_list->next) + { + GdkDevicePrivate *gdkdev = (GdkDevicePrivate *)(tmp_list->data); + + if (gdkdev->info.deviceid != GDK_CORE_POINTER) + { + if (mask != 0 && gdkdev->info.mode != GDK_MODE_DISABLED + && (gdkdev->info.has_cursor || mode == GDK_EXTENSION_EVENTS_ALL)) + gdk_input_enable_window(window,gdkdev); + else + gdk_input_disable_window(window,gdkdev); + } + } +} + +void +gdk_input_window_destroy (GdkWindow *window) +{ + GdkInputWindow *input_window; + + input_window = gdk_input_window_find (window); + g_return_if_fail (input_window != NULL); + + gdk_input_windows = g_list_remove(gdk_input_windows,input_window); + g_free(input_window); +} + +void +gdk_input_exit (void) +{ + GList *tmp_list; + GdkDevicePrivate *gdkdev; + + for (tmp_list = gdk_input_devices; tmp_list; tmp_list = tmp_list->next) + { + gdkdev = (GdkDevicePrivate *)(tmp_list->data); + if (gdkdev->info.deviceid != GDK_CORE_POINTER) + { + gdk_input_set_mode(gdkdev->info.deviceid,GDK_MODE_DISABLED); + + g_free(gdkdev->info.name); +#ifndef XINPUT_NONE + g_free(gdkdev->axes); +#endif + g_free(gdkdev->info.axes); + g_free(gdkdev); + } + } + + g_list_free(gdk_input_devices); + + for (tmp_list = gdk_input_windows; tmp_list; tmp_list = tmp_list->next) + { + g_free(tmp_list->data); + } + g_list_free(gdk_input_windows); +} + +static GdkDevicePrivate * +gdk_input_find_device(guint32 id) +{ + GList *tmp_list = gdk_input_devices; + GdkDevicePrivate *gdkdev; + while (tmp_list) + { + gdkdev = (GdkDevicePrivate *)(tmp_list->data); + if (gdkdev->info.deviceid == id) + return gdkdev; + tmp_list = tmp_list->next; + } + return NULL; +} + +void +gdk_input_window_get_pointer (GdkWindow *window, + guint32 deviceid, + gdouble *x, + gdouble *y, + gdouble *pressure, + gdouble *xtilt, + gdouble *ytilt, + GdkModifierType *mask) +{ + if (gdk_input_vtable.get_pointer) + gdk_input_vtable.get_pointer (window, deviceid, x, y, pressure, + xtilt, ytilt, mask); +} diff --git a/gdk/gdkinput.h b/gdk/gdkinput.h new file mode 100644 index 000000000..21aee6000 --- /dev/null +++ b/gdk/gdkinput.h @@ -0,0 +1,143 @@ +/* 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 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef __GDK_INPUT_H__ +#define __GDK_INPUT_H__ + +#ifndef XINPUT_NONE +#include <X11/extensions/XInput.h> +#endif + +typedef struct _GdkAxisInfo GdkAxisInfo; +typedef struct _GdkInputVTable GdkInputVTable; +typedef struct _GdkDevicePrivate GdkDevicePrivate; +typedef struct _GdkInputWindow GdkInputWindow; + +struct _GdkInputVTable { + gint (*set_mode) (guint32 deviceid, GdkInputMode mode); + void (*set_axes) (guint32 deviceid, GdkAxisUse *axes); + GdkTimeCoord* (*motion_events) (GdkWindow *window, + guint32 deviceid, + guint32 start, + guint32 stop, + gint *nevents_return); + void (*get_pointer) (GdkWindow *window, + guint32 deviceid, + gdouble *x, + gdouble *y, + gdouble *pressure, + gdouble *xtilt, + gdouble *ytilt, + GdkModifierType *mask); + gint (*grab_pointer) (GdkWindow * window, + gint owner_events, + GdkEventMask event_mask, + GdkWindow * confine_to, + guint32 time); + void (*ungrab_pointer) (guint32 time); + + void (*configure_event) (XConfigureEvent *xevent, GdkWindow *window); + void (*enter_event) (XCrossingEvent *xevent, GdkWindow *window); + gint (*other_event) (GdkEvent *event, XEvent *xevent, GdkWindow *window); + /* Handle an unidentified event. Returns TRUE if handled, FALSE + otherwise */ + gint (*window_none_event) (GdkEvent *event, XEvent *xevent); + gint (*enable_window) (GdkWindow *window, GdkDevicePrivate *gdkdev); + gint (*disable_window) (GdkWindow *window, GdkDevicePrivate *gdkdev); +}; + +/* information about a device axis */ +struct _GdkAxisInfo +{ + /* reported x resolution */ + gint xresolution; + + /* reported x minimum/maximum values */ + gint xmin_value, xmax_value; + + /* calibrated resolution (for aspect ration) - only relative values + between axes used */ + gint resolution; + + /* calibrated minimum/maximum values */ + gint min_value, max_value; +}; + +#define GDK_INPUT_NUM_EVENTC 6 + +struct _GdkDevicePrivate { + GdkDeviceInfo info; + +#ifndef XINPUT_NONE + /* information about the axes */ + GdkAxisInfo *axes; + + /* reverse lookup on axis use type */ + gint axis_for_use[GDK_AXIS_LAST]; + + /* Information about XInput device */ + XDevice *xdevice; + + int buttonpress_type, buttonrelease_type, motionnotify_type, + proximityin_type, proximityout_type, changenotify_type; + + /* true if we need to select a different set of events, but + can't because this is the core pointer */ + gint needs_update; + + /* Mask of buttons (used for button grabs) */ + gint button_state; + + /* true if we've claimed the device as active. (used only for XINPUT_GXI) */ + gint claimed; +#endif /* !XINPUT_NONE */ +}; + +struct _GdkInputWindow +{ + /* gdk window */ + GdkWindow *window; + + /* Extension mode (GDK_EXTENSION_EVENTS_ALL/CURSOR) */ + GdkExtensionMode mode; + + /* position relative to root window */ + gint16 root_x; + gint16 root_y; + + /* rectangles relative to window of windows obscuring this one */ + GdkRectangle *obscuring; + gint num_obscuring; + + /* Is there a pointer grab for this window ? */ + gint grabbed; +}; + +/* Global data */ + +extern GdkInputVTable gdk_input_vtable; +/* information about network port and host for gxid daemon */ +extern gchar *gdk_input_gxid_host; +extern gint gdk_input_gxid_port; +extern gint gdk_input_ignore_core; + +/* Function declarations */ + +void gdk_input_window_destroy (GdkWindow *window); + +#endif __GDK_INPUT_H__ diff --git a/gdk/gdkinputcommon.h b/gdk/gdkinputcommon.h new file mode 100644 index 000000000..5e457e0aa --- /dev/null +++ b/gdk/gdkinputcommon.h @@ -0,0 +1,687 @@ +/* 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 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#if defined(XINPUT_GXI) || defined(XINPUT_XFREE) + +/* Forward declarations */ +static void gdk_input_get_root_relative_geometry (Display *dpy, Window w, + int *x_ret, int *y_ret, + int *width_ret, + int *height_ret); +static GdkDevicePrivate *gdk_input_device_new(XDeviceInfo *device, + gint include_core); +static void gdk_input_common_find_events(GdkWindow *window, + GdkDevicePrivate *gdkdev, + gint mask, + XEventClass *classes, + int *num_classes); +static void gdk_input_common_select_events(GdkWindow *window, + GdkDevicePrivate *gdkdev); +static void gdk_input_translate_coordinates(GdkDevicePrivate *gdkdev, + GdkInputWindow *input_window, + gint *axis_data, + gdouble *x, gdouble *y, + gdouble *pressure, + gdouble *xtilt, gdouble *ytilt); +static guint gdk_input_translate_state(guint state, guint device_state); +static gint gdk_input_common_init(gint include_core); +static gint gdk_input_common_other_event (GdkEvent *event, + XEvent *xevent, + GdkInputWindow *input_window, + GdkDevicePrivate *gdkdev); +static void gdk_input_common_set_axes (guint32 deviceid, GdkAxisUse *axes); +static GdkTimeCoord * gdk_input_common_motion_events (GdkWindow *window, + guint32 deviceid, + guint32 start, + guint32 stop, + gint *nevents_return); +static void gdk_input_common_get_pointer (GdkWindow *window, + guint32 deviceid, + gdouble *x, + gdouble *y, + gdouble *pressure, + gdouble *xtilt, + gdouble *ytilt, + GdkModifierType *mask); + +/* Global variables */ + +static gint gdk_input_root_width; +static gint gdk_input_root_height; + +static void +gdk_input_get_root_relative_geometry(Display *dpy, Window w, int *x_ret, int *y_ret, + int *width_ret, int *height_ret) +{ + Window root,parent; + Window *children; + int nchildren; + int x,y,width,height; + int xc,yc,widthc,heightc,border_widthc,depthc; + + XQueryTree(dpy,w,&root,&parent,&children,&nchildren); + if (children) XFree(children); + XGetGeometry(dpy,w,&root,&x,&y,&width,&height,&border_widthc, + &depthc); + x += border_widthc; + y += border_widthc; + + while (root != parent) + { + w = parent; + XQueryTree(dpy,w,&root,&parent,&children,&nchildren); + if (children) XFree(children); + XGetGeometry(dpy,w,&root,&xc,&yc,&widthc,&heightc, + &border_widthc,&depthc); + x += xc + border_widthc; + y += yc + border_widthc; + } + + if (x_ret) + *x_ret = x; + if (y_ret) + *y_ret = y; + if (width_ret) + *width_ret = width; + if (height_ret) + *height_ret = height; +} + +static GdkDevicePrivate * +gdk_input_device_new(XDeviceInfo *device, gint include_core) +{ + GdkDevicePrivate *gdkdev; + gchar *tmp_name, *p; + XAnyClassPtr class; + gint i,j; + + gdkdev = g_new(GdkDevicePrivate,1); + + gdkdev->info.deviceid = device->id; + if (device->name[0]) { + gdkdev->info.name = g_new(char, strlen(device->name)+1); + strcpy(gdkdev->info.name,device->name); + } else { + /* XFree86 3.2 gives an empty name to the default core devices, + (fixed in 3.2A) */ + gdkdev->info.name = g_strdup("pointer"); + strcpy(gdkdev->info.name,"pointer"); + gdkdev->info.source = GDK_SOURCE_MOUSE; + } + + gdkdev->info.mode = GDK_MODE_DISABLED; + + /* Try to figure out what kind of device this is by its name - + could invite a very, very, long list... Lowercase name + for comparison purposes */ + + tmp_name = g_strdup(gdkdev->info.name); + for (p = tmp_name; *p; p++) + { + if (*p >= 'A' && *p <= 'Z') + *p += 'a' - 'A'; + } + + if (!strcmp (tmp_name, "pointer")) + gdkdev->info.source = GDK_SOURCE_MOUSE; + else if (!strcmp (tmp_name, "wacom") || + !strcmp (tmp_name, "pen")) + gdkdev->info.source = GDK_SOURCE_PEN; + else if (!strcmp (tmp_name, "eraser")) + gdkdev->info.source = GDK_SOURCE_ERASER; + else if (!strcmp (tmp_name, "cursor")) + gdkdev->info.source = GDK_SOURCE_CURSOR; + else + gdkdev->info.source = GDK_SOURCE_PEN; + + g_free(tmp_name); + + gdkdev->xdevice = NULL; + + /* step through the classes */ + + gdkdev->info.num_axes = 0; + gdkdev->axes = 0; + gdkdev->info.has_cursor = 0; + gdkdev->needs_update = FALSE; + gdkdev->claimed = FALSE; + gdkdev->button_state = 0; + + class = device->inputclassinfo; + for (i=0;i<device->num_classes;i++) + { + switch (class->class) { + case ButtonClass: + { + break; + } + case ValuatorClass: + { + XValuatorInfo *xvi = (XValuatorInfo *)class; + gdkdev->info.num_axes = xvi->num_axes; + gdkdev->axes = g_new(GdkAxisInfo, xvi->num_axes); + gdkdev->info.axes = g_new(GdkAxisUse, xvi->num_axes); + for (j=0;j<xvi->num_axes;j++) + { + gdkdev->axes[j].resolution = + gdkdev->axes[j].xresolution = xvi->axes[j].resolution; + gdkdev->axes[j].min_value = + gdkdev->axes[j].xmin_value = xvi->axes[j].min_value; + gdkdev->axes[j].max_value = + gdkdev->axes[j].xmax_value = xvi->axes[j].max_value; + gdkdev->info.axes[j] = GDK_AXIS_IGNORE; + } + j=0; + if (j<xvi->num_axes) + gdkdev->info.axes[j++] = GDK_AXIS_X; + if (j<xvi->num_axes) + gdkdev->info.axes[j++] = GDK_AXIS_Y; + if (j<xvi->num_axes) + gdkdev->info.axes[j++] = GDK_AXIS_PRESSURE; + if (j<xvi->num_axes) + gdkdev->info.axes[j++] = GDK_AXIS_XTILT; + if (j<xvi->num_axes) + gdkdev->info.axes[j++] = GDK_AXIS_YTILT; + + /* set up reverse lookup on axis use */ + for (j=GDK_AXIS_IGNORE;j<GDK_AXIS_LAST;j++) + gdkdev->axis_for_use[j] = -1; + + for (j=0;j<xvi->num_axes;j++) + if (gdkdev->info.axes[j] != GDK_AXIS_IGNORE) + gdkdev->axis_for_use[gdkdev->info.axes[j]] = j; + + break; + } + } + class = (XAnyClassPtr)(((char *)class) + class->length); + } + /* return NULL if no axes */ + if (!gdkdev->info.num_axes || !gdkdev->axes || + (!include_core && device->use == IsXPointer)) + { + g_free(gdkdev->info.name); + if (gdkdev->axes) + g_free(gdkdev->axes); + g_free(gdkdev); + return NULL; + } + + if (device->use != IsXPointer) + gdkdev->xdevice = XOpenDevice(gdk_display, gdkdev->info.deviceid); + + return gdkdev; +} + +static void +gdk_input_common_find_events(GdkWindow *window, + GdkDevicePrivate *gdkdev, + gint mask, + XEventClass *classes, + int *num_classes) +{ + gint i; + XEventClass class; + + i = 0; + /* We have to track press and release events in pairs to keep + track of button state correctly and implement grabbing */ + if (mask & GDK_BUTTON_PRESS_MASK || mask & GDK_BUTTON_RELEASE_MASK) + { + DeviceButtonPress (gdkdev->xdevice, gdkdev->buttonpress_type, + class); + if (class != 0) + classes[i++] = class; + DeviceButtonRelease (gdkdev->xdevice, gdkdev->buttonrelease_type, + class); + if (class != 0) + classes[i++] = class; + } + if (mask & GDK_POINTER_MOTION_MASK) + { + DeviceMotionNotify (gdkdev->xdevice, gdkdev->motionnotify_type, class); + if (class != 0) + classes[i++] = class; + } + if (mask & GDK_POINTER_MOTION_HINT_MASK) + { + /* We'll get into trouble if the macros change, but at least we'll + know about it, and we avoid warnings now */ + DevicePointerMotionHint (gdkdev->xdevice, 0, class); + if (class != 0) + classes[i++] = class; + } + if (mask & GDK_PROXIMITY_IN_MASK) + { + ProximityIn (gdkdev->xdevice, gdkdev->proximityin_type, class); + if (class != 0) + classes[i++] = class; + } + if (mask & GDK_PROXIMITY_OUT_MASK) + { + ProximityOut (gdkdev->xdevice, gdkdev->proximityout_type, class); + if (class != 0) + classes[i++] = class; + } + + *num_classes = i; +} + +static void +gdk_input_common_select_events(GdkWindow *window, + GdkDevicePrivate *gdkdev) +{ + XEventClass classes[6]; + gint num_classes; + + if (gdkdev->info.mode == GDK_MODE_DISABLED) + gdk_input_common_find_events(window, gdkdev, 0, classes, &num_classes); + else + gdk_input_common_find_events(window, gdkdev, + ((GdkWindowPrivate *)window)->extension_events, + classes, &num_classes); + + XSelectExtensionEvent (gdk_display, + GDK_WINDOW_XWINDOW(window), + classes, num_classes); +} + +gint +gdk_input_common_init(gint include_core) +{ + char **extensions; + XDeviceInfo *devices; + int num_devices; + int num_extensions, loop; + Display *display = gdk_display; + + /* Init global vars */ + gdk_window_get_geometry(NULL, /* use root window */ + NULL,NULL, + &gdk_input_root_width,&gdk_input_root_height, + NULL); + + /* Init XInput extension */ + + extensions = XListExtensions(display, &num_extensions); + for (loop = 0; loop < num_extensions && + (strcmp(extensions[loop], "XInputExtension") != 0); loop++); + XFreeExtensionList(extensions); + if (loop == num_extensions) /* XInput extension not found */ + return FALSE; + + gdk_input_devices = 0; + devices = XListInputDevices(display, &num_devices); + + for(loop=0; loop<num_devices; loop++) + { + GdkDevicePrivate *gdkdev = gdk_input_device_new(&devices[loop], + include_core); + if (gdkdev) + gdk_input_devices = g_list_append(gdk_input_devices, gdkdev); + } + XFreeDeviceList(devices); + + gdk_input_devices = g_list_append (gdk_input_devices, &gdk_input_core_info); + + return TRUE; +} + +static void +gdk_input_translate_coordinates (GdkDevicePrivate *gdkdev, + GdkInputWindow *input_window, + gint *axis_data, + gdouble *x, gdouble *y, gdouble *pressure, + gdouble *xtilt, gdouble *ytilt) +{ + GdkWindowPrivate *win_priv; + + int x_axis, y_axis, pressure_axis, xtilt_axis, ytilt_axis; + + double device_width, device_height; + double x_offset, y_offset, x_scale, y_scale; + + win_priv = (GdkWindowPrivate *) input_window->window; + + x_axis = gdkdev->axis_for_use[GDK_AXIS_X]; + y_axis = gdkdev->axis_for_use[GDK_AXIS_Y]; + pressure_axis = gdkdev->axis_for_use[GDK_AXIS_PRESSURE]; + xtilt_axis = gdkdev->axis_for_use[GDK_AXIS_XTILT]; + ytilt_axis = gdkdev->axis_for_use[GDK_AXIS_YTILT]; + + device_width = gdkdev->axes[x_axis].max_value - + gdkdev->axes[x_axis].min_value; + device_height = gdkdev->axes[y_axis].max_value - + gdkdev->axes[y_axis].min_value; + + if (gdkdev->info.mode == GDK_MODE_SCREEN) + { + x_scale = gdk_input_root_width / device_width; + y_scale = gdk_input_root_height / device_height; + + x_offset = - input_window->root_x; + y_offset = - input_window->root_y; + } + else /* GDK_MODE_WINDOW */ + { + double device_aspect = (device_height*gdkdev->axes[y_axis].resolution) / + (device_width*gdkdev->axes[x_axis].resolution); + + if (device_aspect * win_priv->width >= win_priv->height) + { + /* device taller than window */ + x_scale = win_priv->width / device_width; + y_scale = (x_scale * gdkdev->axes[x_axis].resolution) + / gdkdev->axes[y_axis].resolution; + + x_offset = 0; + y_offset = -(device_height * y_scale - + win_priv->height)/2; + } + else + { + /* window taller than device */ + y_scale = win_priv->height / device_height; + x_scale = (y_scale * gdkdev->axes[y_axis].resolution) + / gdkdev->axes[x_axis].resolution; + + y_offset = 0; + x_offset = - (device_width * x_scale - win_priv->width)/2; + } + } + + if (x) *x = x_offset + x_scale*axis_data[x_axis]; + if (y) *y = y_offset + y_scale*axis_data[y_axis]; + + if (pressure) + { + if (pressure_axis != -1) + *pressure = ((double)axis_data[pressure_axis] + - gdkdev->axes[pressure_axis].min_value) + / (gdkdev->axes[pressure_axis].max_value + - gdkdev->axes[pressure_axis].min_value); + else + *pressure = 0.5; + } + + if (xtilt) + { + if (xtilt_axis != -1) + { + *xtilt = 2. * (double)(axis_data[xtilt_axis] - + (gdkdev->axes[xtilt_axis].min_value + + gdkdev->axes[xtilt_axis].max_value)/2) / + (gdkdev->axes[xtilt_axis].max_value - + gdkdev->axes[xtilt_axis].min_value); + } + else *xtilt = 0; + } + + if (ytilt) + { + if (ytilt_axis != -1) + { + *ytilt = 2. * (double)(axis_data[ytilt_axis] - + (gdkdev->axes[ytilt_axis].min_value + + gdkdev->axes[ytilt_axis].max_value)/2) / + (gdkdev->axes[ytilt_axis].max_value - + gdkdev->axes[ytilt_axis].min_value); + } + else + *ytilt = 0; + } +} + +/* combine the state of the core device and the device state + into one - for now we do this in a simple-minded manner - + we just take the keyboard portion of the core device and + the button portion (all of?) the device state. + Any button remapping should go on here. */ +static guint +gdk_input_translate_state(guint state, guint device_state) +{ + return device_state | (state & 0xFF); +} + +static gint +gdk_input_common_other_event (GdkEvent *event, + XEvent *xevent, + GdkInputWindow *input_window, + GdkDevicePrivate *gdkdev) +{ + if ((xevent->type == gdkdev->buttonpress_type) || + (xevent->type == gdkdev->buttonrelease_type)) + { + XDeviceButtonEvent *xdbe = (XDeviceButtonEvent *)(xevent); + + if (xdbe->type == gdkdev->buttonpress_type) + { + event->button.type = GDK_BUTTON_PRESS; + gdkdev->button_state |= 1 << xdbe->button; + } + else + { + event->button.type = GDK_BUTTON_RELEASE; + gdkdev->button_state &= ~(1 << xdbe->button); + } + event->button.window = input_window->window; + event->button.time = xdbe->time; + event->button.source = gdkdev->info.source; + event->button.deviceid = xdbe->deviceid; + + gdk_input_translate_coordinates (gdkdev,input_window, xdbe->axis_data, + &event->button.x,&event->button.y, + &event->button.pressure, + &event->button.xtilt, + &event->button.ytilt); + event->button.state = gdk_input_translate_state(xdbe->state,xdbe->device_state); + event->button.button = xdbe->button; + + return TRUE; + } + + if (xevent->type == gdkdev->motionnotify_type) + { + XDeviceMotionEvent *xdme = (XDeviceMotionEvent *)(xevent); + + gdk_input_translate_coordinates(gdkdev,input_window,xdme->axis_data, + &event->motion.x,&event->motion.y, + &event->motion.pressure, + &event->motion.xtilt, + &event->motion.ytilt); + + event->motion.type = GDK_MOTION_NOTIFY; + event->motion.window = input_window->window; + event->motion.time = xdme->time; + event->motion.deviceid = xdme->deviceid; + event->motion.state = gdk_input_translate_state(xdme->state, + xdme->device_state); + event->motion.source = gdkdev->info.source; + event->motion.deviceid = xdme->deviceid; + + if (gdk_show_events) + g_print ("motion notify:\t\twindow: %ld device: %ld x,y: %f %f hint: %s\n", + xdme->window, + xdme->deviceid, + event->motion.x, event->motion.y, + (xevent->xmotion.is_hint) ? "true" : "false"); + + + return TRUE; + } + + if (xevent->type == gdkdev->proximityin_type || + xevent->type == gdkdev->proximityout_type) + { + XProximityNotifyEvent *xpne = (XProximityNotifyEvent *)(xevent); + + event->proximity.type = (xevent->type == gdkdev->proximityin_type)? + GDK_PROXIMITY_IN:GDK_PROXIMITY_OUT; + event->proximity.window = input_window->window; + event->proximity.time = xpne->time; + event->proximity.source = gdkdev->info.source; + event->proximity.deviceid = xpne->deviceid; + + return TRUE; + } + + return -1; /* wasn't one of our event types */ +} + +static void +gdk_input_common_set_axes (guint32 deviceid, GdkAxisUse *axes) +{ + int i; + GdkDevicePrivate *gdkdev = gdk_input_find_device(deviceid); + g_return_if_fail (gdkdev != NULL); + + for (i=GDK_AXIS_IGNORE;i<GDK_AXIS_LAST;i++) + { + gdkdev->axis_for_use[i] = -1; + } + + for (i=0;i<gdkdev->info.num_axes;i++) + { + gdkdev->info.axes[i] = axes[i]; + gdkdev->axis_for_use[axes[i]] = i; + } +} + +static GdkTimeCoord * +gdk_input_common_motion_events (GdkWindow *window, + guint32 deviceid, + guint32 start, + guint32 stop, + gint *nevents_return) +{ + GdkTimeCoord *coords; + XDeviceTimeCoord *device_coords; + GdkInputWindow *input_window; + GdkDevicePrivate *gdkdev; + + int mode_return; + int axis_count_return; + int i; + + gdkdev = gdk_input_find_device (deviceid); + input_window = gdk_input_window_find (window); + + g_return_val_if_fail (gdkdev != NULL, NULL); + g_return_val_if_fail (gdkdev->xdevice != NULL, NULL); + g_return_val_if_fail (input_window != NULL, NULL); + + device_coords = XGetDeviceMotionEvents (gdk_display, + gdkdev->xdevice, + start, stop, + nevents_return, &mode_return, + &axis_count_return); + + if (device_coords) + { + coords = g_new (GdkTimeCoord, *nevents_return); + + for (i=0; i<*nevents_return; i++) + { + gdk_input_translate_coordinates (gdkdev, input_window, + device_coords[i].data, + &coords[i].x, &coords[i].y, + &coords[i].pressure, + &coords[i].xtilt, &coords[i].ytilt); + } + XFreeDeviceMotionEvents (device_coords); + + return coords; + } + else + return NULL; +} + +static void +gdk_input_common_get_pointer (GdkWindow *window, + guint32 deviceid, + gdouble *x, + gdouble *y, + gdouble *pressure, + gdouble *xtilt, + gdouble *ytilt, + GdkModifierType *mask) +{ + GdkDevicePrivate *gdkdev; + GdkInputWindow *input_window; + XDeviceState *state; + XInputClass *input_class; + gint x_int, y_int; + gint i; + + /* we probably need to get the mask in any case */ + + if (deviceid == GDK_CORE_POINTER) + { + gdk_window_get_pointer (window, &x_int, &y_int, mask); + if (x) *x = x_int; + if (y) *y = y_int; + if (pressure) *pressure = 0.5; + if (xtilt) *xtilt = 0; + if (ytilt) *ytilt = 0; + } + else + { + if (mask) + gdk_window_get_pointer (window, NULL, NULL, mask); + + gdkdev = gdk_input_find_device (deviceid); + input_window = gdk_input_window_find (window); + + g_return_if_fail (gdkdev != NULL); + g_return_if_fail (gdkdev->xdevice != NULL); + g_return_if_fail (input_window != NULL); + + state = XQueryDeviceState (gdk_display, gdkdev->xdevice); + input_class = state->data; + for (i=0; i<state->num_classes; i++) + { + switch (input_class->class) + { + case ValuatorClass: + gdk_input_translate_coordinates(gdkdev, input_window, + ((XValuatorState *)input_class)->valuators, + x, y, pressure, + xtilt, ytilt); + + + break; + case ButtonClass: + if (mask) + { + *mask &= ~(GDK_BUTTON1_MASK | GDK_BUTTON2_MASK | + GDK_BUTTON3_MASK | GDK_BUTTON4_MASK | + GDK_BUTTON5_MASK); + for (i=0; i < ((XButtonState *)input_class)->num_buttons; i++) + { + if (((XButtonState *)input_class)->buttons[i]) + *mask |= GDK_BUTTON1_MASK << i; + } + } + break; + } + input_class = (XInputClass *)(((char *)input_class)+input_class->length); + } + } +} + +#endif diff --git a/gdk/gdkinputgxi.h b/gdk/gdkinputgxi.h new file mode 100644 index 000000000..a30e05f95 --- /dev/null +++ b/gdk/gdkinputgxi.h @@ -0,0 +1,628 @@ +/* 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 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifdef XINPUT_GXI + +/* #define DEBUG_SWITCHING */ + +#include <gxid_lib.h> + +/* Forward declarations */ +static void gdk_input_gxi_select_notify (GdkDevicePrivate *gdkdev); +static gint gdk_input_gxi_set_mode (guint32 deviceid, GdkInputMode mode); +static gint gdk_input_is_extension_device (guint32 deviceid); +static void gdk_input_gxi_configure_event (XConfigureEvent *xevent, + GdkWindow *window); +static void gdk_input_gxi_enter_event (XCrossingEvent *xevent, + GdkWindow *window); +static gint gdk_input_gxi_other_event (GdkEvent *event, + XEvent *xevent, + GdkWindow *window); +static void gdk_input_gxi_update_device (GdkDevicePrivate *gdkdev); + +static gint gdk_input_gxi_window_none_event (GdkEvent *event, XEvent *xevent); +static gint gdk_input_gxi_enable_window (GdkWindow *window, + GdkDevicePrivate *gdkdev); +static gint gdk_input_gxi_disable_window (GdkWindow *window, + GdkDevicePrivate *gdkdev); +static Window gdk_input_find_root_child(Display *dpy, Window w); +static void gdk_input_compute_obscuring(GdkInputWindow *input_window); +static gint gdk_input_is_obscured(GdkInputWindow *input_window, gdouble x, + gdouble y); +static GdkTimeCoord *gdk_input_gxi_motion_events (GdkWindow *window, + guint32 deviceid, + guint32 start, + guint32 stop, + gint *nevents_return); +static void gdk_input_gxi_get_pointer (GdkWindow *window, + guint32 deviceid, + gdouble *x, + gdouble *y, + gdouble *pressure, + gdouble *xtilt, + gdouble *ytilt, + GdkModifierType *mask); +static gint gdk_input_gxi_grab_pointer (GdkWindow * window, + gint owner_events, + GdkEventMask event_mask, + GdkWindow * confine_to, + guint32 time); +static void gdk_input_gxi_ungrab_pointer (guint32 time); + +/* Local variables */ + +static GdkDevicePrivate *gdk_input_current_device; +static GdkDevicePrivate *gdk_input_core_pointer; + +void +gdk_input_init(void) +{ + GList *tmp_list; + + gdk_input_vtable.set_mode = gdk_input_gxi_set_mode; + gdk_input_vtable.set_axes = gdk_input_common_set_axes; + gdk_input_vtable.motion_events = gdk_input_gxi_motion_events; + gdk_input_vtable.get_pointer = gdk_input_gxi_get_pointer; + gdk_input_vtable.grab_pointer = gdk_input_gxi_grab_pointer; + gdk_input_vtable.ungrab_pointer = gdk_input_gxi_ungrab_pointer; + gdk_input_vtable.configure_event = gdk_input_gxi_configure_event; + gdk_input_vtable.enter_event = gdk_input_gxi_enter_event; + gdk_input_vtable.other_event = gdk_input_gxi_other_event; + gdk_input_vtable.window_none_event = gdk_input_gxi_window_none_event; + gdk_input_vtable.enable_window = gdk_input_gxi_enable_window; + gdk_input_vtable.disable_window = gdk_input_gxi_disable_window; + + gdk_input_ignore_core = FALSE; + gdk_input_core_pointer = NULL; + + if (!gdk_input_gxid_host) + { + gdk_input_gxid_host = getenv("GXID_HOST"); + } + if (!gdk_input_gxid_port) + { + char *t = getenv("GXID_PORT"); + if (t) + gdk_input_gxid_port = atoi(t); + } + + gdk_input_common_init(TRUE); + + /* find initial core pointer */ + + for (tmp_list = gdk_input_devices; tmp_list; tmp_list = tmp_list->next) + { + GdkDevicePrivate *gdkdev = (GdkDevicePrivate *)tmp_list->data; + if (gdk_input_is_extension_device(gdkdev->info.deviceid)) + { + gdk_input_gxi_select_notify (gdkdev); + } + else + { + if (gdkdev->info.deviceid != GDK_CORE_POINTER) + gdk_input_core_pointer = gdkdev; + } + } +} + +static void +gdk_input_gxi_select_notify (GdkDevicePrivate *gdkdev) +{ + XEventClass class; + + ChangeDeviceNotify (gdkdev->xdevice, gdkdev->changenotify_type, class); + + XSelectExtensionEvent (gdk_display, gdk_root_window, &class, 1); +} + +/* Set the core pointer. Device should already be enabled. */ +static gint +gdk_input_gxi_set_core_pointer(GdkDevicePrivate *gdkdev) +{ + int x_axis,y_axis; + + g_return_val_if_fail(gdkdev->xdevice,FALSE); + + x_axis = gdkdev->axis_for_use[GDK_AXIS_X]; + y_axis = gdkdev->axis_for_use[GDK_AXIS_Y]; + + g_return_val_if_fail(x_axis != -1 && y_axis != -1,FALSE); + + /* core_pointer might not be up to date so we check with the server + before change the pointer */ + + if ( !gdk_input_is_extension_device(gdkdev->info.deviceid) ) + { +#if 0 + if (gdkdev != gdk_input_core_pointer) + g_warning("core pointer inconsistency"); +#endif + return TRUE; + } + + if ( XChangePointerDevice(gdk_display,gdkdev->xdevice, x_axis, y_axis) + != Success ) + { + return FALSE; + } + else + { + gdk_input_gxi_update_device (gdk_input_core_pointer); + gdk_input_core_pointer = gdkdev; + return TRUE; + } +} + + +/* FIXME, merge with gdk_input_xfree_set_mode */ + +static gint +gdk_input_gxi_set_mode (guint32 deviceid, GdkInputMode mode) +{ + GList *tmp_list; + GdkDevicePrivate *gdkdev; + GdkInputMode old_mode; + GdkInputWindow *input_window; + + gdkdev = gdk_input_find_device(deviceid); + g_return_val_if_fail (gdkdev != NULL,FALSE); + old_mode = gdkdev->info.mode; + + if (gdkdev->info.mode == mode) + return TRUE; + + gdkdev->info.mode = mode; + + if (old_mode != GDK_MODE_DISABLED) + { + for (tmp_list = gdk_input_windows; tmp_list; tmp_list = tmp_list->next) + { + input_window = (GdkInputWindow *)tmp_list->data; + if (input_window->mode != GDK_EXTENSION_EVENTS_CURSOR) + gdk_input_disable_window (input_window->window, gdkdev); + } + } + + if (mode != GDK_MODE_DISABLED) + { + for (tmp_list = gdk_input_windows; tmp_list; tmp_list = tmp_list->next) + { + input_window = (GdkInputWindow *)tmp_list->data; + if (input_window->mode != GDK_EXTENSION_EVENTS_CURSOR) + if (!gdk_input_enable_window(input_window->window, gdkdev)) + { + gdk_input_set_mode(deviceid, old_mode); + return FALSE; + } + } + } + + return TRUE; + +} + +gint +gdk_input_is_extension_device (guint32 deviceid) +{ + XDeviceInfo *devices; + int num_devices, loop; + + if (deviceid == GDK_CORE_POINTER) + return FALSE; + + devices = XListInputDevices(gdk_display, &num_devices); + for(loop=0; loop<num_devices; loop++) + { + if ((devices[loop].id == deviceid) && (devices[loop].use == IsXExtensionDevice)) + { + XFreeDeviceList(devices); + return TRUE; + } + } + + XFreeDeviceList(devices); + return FALSE; +} + +static void +gdk_input_gxi_configure_event (XConfigureEvent *xevent, GdkWindow *window) +{ + GdkInputWindow *input_window; + gint root_x, root_y; + + input_window = gdk_input_window_find(window); + g_return_if_fail (input_window != NULL); + + gdk_input_get_root_relative_geometry(gdk_display,GDK_WINDOW_XWINDOW(window), + &root_x, &root_y, NULL, NULL); + input_window->root_x = root_x; + input_window->root_y = root_y; + gdk_input_compute_obscuring(input_window); +} + +static void +gdk_input_gxi_enter_event (XCrossingEvent *xevent, GdkWindow *window) +{ + GdkInputWindow *input_window; + + input_window = gdk_input_window_find(window); + g_return_if_fail (input_window != NULL); + + gdk_input_compute_obscuring(input_window); +} + +static gint +gdk_input_gxi_other_event (GdkEvent *event, + XEvent *xevent, + GdkWindow *window) +{ + GdkInputWindow *input_window; + + GdkDevicePrivate *gdkdev; + gint return_val; + + input_window = gdk_input_window_find(window); + g_return_val_if_fail (window != NULL, -1); + + /* This is a sort of a hack, as there isn't any XDeviceAnyEvent - + but it's potentially faster than scanning through the types of + every device. If we were deceived, then it won't match any of + the types for the device anyways */ + gdkdev = gdk_input_find_device(((XDeviceButtonEvent *)xevent)->deviceid); + + if (!gdkdev) { + return -1; /* we don't handle it - not an XInput event */ + } + + if (gdkdev->info.mode == GDK_MODE_DISABLED || + input_window->mode == GDK_EXTENSION_EVENTS_CURSOR) + return FALSE; + + if (gdkdev != gdk_input_current_device && + xevent->type != gdkdev->changenotify_type) + { + gdk_input_current_device = gdkdev; + } + + return_val = gdk_input_common_other_event (event, xevent, + input_window, gdkdev); + + if (return_val > 0 && event->type == GDK_MOTION_NOTIFY && + (!gdkdev->button_state) && (!input_window->grabbed) && + ((event->motion.x < 0) || (event->motion.y < 0) || + (event->motion.x > ((GdkWindowPrivate *)window)->width) || + (event->motion.y > ((GdkWindowPrivate *)window)->height) || + gdk_input_is_obscured(input_window,event->motion.x,event->motion.y))) + { +#ifdef DEBUG_SWITCHING + g_print("gdkinput: Setting core pointer to %d on motion at (%f,%f)\n", + gdkdev->info.deviceid,event->motion.x,event->motion.y); + g_print(" window geometry is: %dx%d\n", + ((GdkWindowPrivate *)window)->width, + ((GdkWindowPrivate *)window)->height); +#endif + gdk_input_gxi_set_core_pointer(gdkdev); + return FALSE; + } + else + return return_val; + +} + +static void +gdk_input_gxi_update_device (GdkDevicePrivate *gdkdev) +{ + GList *t; + + if (gdk_input_is_extension_device (gdkdev->info.deviceid)) + { + if (!gdkdev->xdevice) + { + gdkdev->xdevice = XOpenDevice(gdk_display, gdkdev->info.deviceid); + gdk_input_gxi_select_notify (gdkdev); + gdkdev->needs_update = 1; + } + if (gdkdev->needs_update && gdkdev->xdevice) + { + for (t = gdk_input_windows; t; t = t->next) + gdk_input_common_select_events (((GdkInputWindow *)t->data)->window, + gdkdev); + gdkdev->needs_update = 0; + } + } +} + +static gint +gdk_input_gxi_window_none_event (GdkEvent *event, XEvent *xevent) +{ + GdkDevicePrivate *gdkdev = + gdk_input_find_device(((XDeviceButtonEvent *)xevent)->deviceid); + + if (!gdkdev) { + return -1; /* we don't handle it - not an XInput event */ + } + + if (xevent->type == gdkdev->changenotify_type) + { + if (gdk_input_core_pointer != gdkdev) + { +#ifdef DEBUG_SWITCHING + g_print("ChangeNotify from %d to %d:\n", + gdk_input_core_pointer->info.deviceid, + gdkdev->info.deviceid); +#endif + gdk_input_gxi_update_device (gdk_input_core_pointer); + gdk_input_core_pointer = gdkdev; + } + } + + return FALSE; +} + +static gint +gdk_input_gxi_enable_window (GdkWindow *window, GdkDevicePrivate *gdkdev) +{ + GdkInputWindow *input_window; + + input_window = gdk_input_window_find (window); + g_return_val_if_fail (input_window != NULL, FALSE); + + if (!gdkdev->claimed) + { + if (gxid_claim_device(gdk_input_gxid_host, gdk_input_gxid_port, + gdkdev->info.deviceid, + GDK_WINDOW_XWINDOW(window), FALSE) != + GXID_RETURN_OK) + { + g_warning("Could not get device (is gxid running?)\n"); + return FALSE; + } + gdkdev->claimed = TRUE; + } + + if (gdkdev->xdevice && gdkdev != gdk_input_core_pointer) + gdk_input_common_select_events(window, gdkdev); + else + gdkdev->needs_update = TRUE; + + return TRUE; +} + +static gint +gdk_input_gxi_disable_window(GdkWindow *window, GdkDevicePrivate *gdkdev) +{ + GdkInputWindow *input_window; + + input_window = gdk_input_window_find (window); + g_return_val_if_fail (input_window != NULL, FALSE); + + if (gdkdev->claimed) + { + gxid_release_device(gdk_input_gxid_host, gdk_input_gxid_port, + gdkdev->info.deviceid, + GDK_WINDOW_XWINDOW(window)); + + gdkdev->claimed = FALSE; + } + + if (gdkdev->xdevice && gdkdev != gdk_input_core_pointer) + gdk_input_common_select_events(window, gdkdev); + else + gdkdev->needs_update = TRUE; + + return TRUE; +} + +static gint +gdk_input_is_obscured(GdkInputWindow *input_window, gdouble x, gdouble y) +{ + int i; + for (i=0;i<input_window->num_obscuring;i++) + { + GdkRectangle *rect = &input_window->obscuring[i]; + if ((x >= rect->x) && + (y >= rect->y) && + (x < rect->x + rect->width) && + (y < rect->y + rect->height)) + return TRUE; + } + return FALSE; +} + +/* If this routine needs fixing, the corresponding routine + in gxid.c will need it too. */ + +static Window +gdk_input_find_root_child(Display *dpy, Window w) +{ + Window root,parent; + Window *children; + int nchildren; + + parent = w; + do + { + w = parent; + XQueryTree(dpy,w,&root,&parent,&children,&nchildren); + if (children) XFree(children); + } + while (parent != root); + + return w; +} + +void +gdk_input_compute_obscuring(GdkInputWindow *input_window) +{ + int i; + int x,y,width,height; + int xc,yc,widthc,heightc,border_widthc,depthc; + + Window root,parent; + Window *children; + int nchildren; + + Window w = GDK_WINDOW_XWINDOW(input_window->window); + Window root_child = gdk_input_find_root_child(gdk_display,w); + gdk_input_get_root_relative_geometry(gdk_display,w,&x,&y,&width,&height); + + input_window->root_x = x; + input_window->root_y = y; + + XQueryTree(gdk_display,GDK_ROOT_WINDOW(), + &root,&parent,&children,&nchildren); + + + if (input_window->obscuring) + g_free(input_window->obscuring); + input_window->obscuring = 0; + input_window->num_obscuring = 0; + + for (i=0;i<nchildren;i++) + if (children[i] == root_child) + break; + + if (i>=nchildren-1) + { + if (nchildren) + XFree(children); + return; + } + + input_window->obscuring = g_new(GdkRectangle,(nchildren-i-1)); + + for (i=i+1;i<nchildren;i++) + { + int xmin, xmax, ymin, ymax; + XGetGeometry(gdk_display,children[i],&root,&xc,&yc,&widthc,&heightc, + &border_widthc, &depthc); + xmin = xc>x ? xc : x; + xmax = (xc+widthc)<(x+width) ? xc+widthc : x+width; + ymin = yc>y ? yc : y; + ymax = (yc+heightc)<(y+height) ? yc+heightc : y+height; + if ((xmin < xmax) && (ymin < ymax)) + { + XWindowAttributes attributes; + XGetWindowAttributes(gdk_display,children[i],&attributes); + if (attributes.map_state == IsViewable) + { + GdkRectangle *rect = &input_window->obscuring[input_window->num_obscuring]; + + /* we store the whole window, not just the obscuring part */ + rect->x = xc - x; + rect->y = yc - y; + rect->width = widthc; + rect->height = heightc; + input_window->num_obscuring++; + } + } + } + + if (nchildren) + XFree(children); +} + +static void +gdk_input_gxi_get_pointer (GdkWindow *window, + guint32 deviceid, + gdouble *x, + gdouble *y, + gdouble *pressure, + gdouble *xtilt, + gdouble *ytilt, + GdkModifierType *mask) +{ + GdkDevicePrivate *gdkdev; + + gdkdev = gdk_input_find_device (deviceid); + g_return_if_fail (gdkdev != NULL); + + if (gdkdev == gdk_input_core_pointer) + gdk_input_common_get_pointer (window, GDK_CORE_POINTER, x, y, + pressure, xtilt, ytilt, mask); + else + gdk_input_common_get_pointer (window, deviceid, x, y, + pressure, xtilt, ytilt, mask); +} + +static GdkTimeCoord * +gdk_input_gxi_motion_events (GdkWindow *window, + guint32 deviceid, + guint32 start, + guint32 stop, + gint *nevents_return) +{ + GdkDevicePrivate *gdkdev; + + gdkdev = gdk_input_find_device (deviceid); + g_return_val_if_fail (gdkdev != NULL, NULL); + + + if (gdkdev == gdk_input_core_pointer) + return gdk_input_motion_events (window, GDK_CORE_POINTER, start, stop, + nevents_return); + else + return gdk_input_common_motion_events (window, deviceid, start, stop, + nevents_return); + +} + +static gint +gdk_input_gxi_grab_pointer (GdkWindow * window, + gint owner_events, + GdkEventMask event_mask, + GdkWindow * confine_to, + guint32 time) +{ + GdkInputWindow *input_window, *new_window; + GList *tmp_list; + + tmp_list = gdk_input_windows; + while (tmp_list) + { + input_window = (GdkInputWindow *)tmp_list->data; + if (input_window->grabbed) + return AlreadyGrabbed; + + if (input_window->window == window) + new_window = input_window; + + tmp_list = tmp_list->next; + } + + new_window->grabbed = TRUE; + return Success; +} + +static void +gdk_input_gxi_ungrab_pointer (guint32 time) +{ + GdkInputWindow *input_window; + GList *tmp_list; + + tmp_list = gdk_input_windows; + while (tmp_list) + { + input_window = (GdkInputWindow *)tmp_list->data; + if (input_window->grabbed) + input_window->grabbed = FALSE; + tmp_list = tmp_list->next; + } +} + +#endif /* XINPUT_GXI */ diff --git a/gdk/gdkinputnone.h b/gdk/gdkinputnone.h new file mode 100644 index 000000000..8ae8c4189 --- /dev/null +++ b/gdk/gdkinputnone.h @@ -0,0 +1,72 @@ +/* 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 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifdef XINPUT_NONE + +static void gdk_input_none_get_pointer (GdkWindow *window, + guint32 deviceid, + gdouble *x, + gdouble *y, + gdouble *pressure, + gdouble *xtilt, + gdouble *ytilt, + GdkModifierType *mask); + +void +gdk_input_init () +{ + gdk_input_vtable.set_mode = NULL; + gdk_input_vtable.set_axes = NULL; + gdk_input_vtable.motion_events = NULL; + gdk_input_vtable.get_pointer = gdk_input_none_get_pointer; + gdk_input_vtable.grab_pointer = NULL; + gdk_input_vtable.ungrab_pointer = NULL; + gdk_input_vtable.configure_event = NULL; + gdk_input_vtable.enter_event = NULL; + gdk_input_vtable.other_event = NULL; + gdk_input_vtable.window_none_event = NULL; + gdk_input_vtable.enable_window = NULL; + gdk_input_vtable.disable_window = NULL; + + gdk_input_devices = g_list_append (NULL, &gdk_input_core_info); + + gdk_input_ignore_core = FALSE; +} + +static void +gdk_input_none_get_pointer (GdkWindow *window, + guint32 deviceid, + gdouble *x, + gdouble *y, + gdouble *pressure, + gdouble *xtilt, + gdouble *ytilt, + GdkModifierType *mask) +{ + gint x_int, y_int; + + gdk_window_get_pointer (window, &x_int, &y_int, mask); + + if (x) *x = x_int; + if (y) *y = y_int; + if (pressure) *pressure = 0.5; + if (xtilt) *xtilt = 0; + if (ytilt) *ytilt = 0; +} + +#endif /* XINPUT_NONE */ diff --git a/gdk/gdkinputxfree.h b/gdk/gdkinputxfree.h new file mode 100644 index 000000000..f74249008 --- /dev/null +++ b/gdk/gdkinputxfree.h @@ -0,0 +1,368 @@ +/* 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 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifdef XINPUT_XFREE + +/* forward declarations */ + +static gint gdk_input_xfree_set_mode (guint32 deviceid, GdkInputMode mode); +static void gdk_input_check_proximity(); +static void gdk_input_xfree_configure_event (XConfigureEvent *xevent, + GdkWindow *window); +static void gdk_input_xfree_enter_event (XCrossingEvent *xevent, + GdkWindow *window); +static gint gdk_input_xfree_other_event (GdkEvent *event, + XEvent *xevent, + GdkWindow *window); +static gint gdk_input_xfree_enable_window(GdkWindow *window, + GdkDevicePrivate *gdkdev); +static gint gdk_input_xfree_disable_window(GdkWindow *window, + GdkDevicePrivate *gdkdev); +static gint gdk_input_xfree_grab_pointer (GdkWindow * window, + gint owner_events, + GdkEventMask event_mask, + GdkWindow * confine_to, + guint32 time); +static void gdk_input_xfree_ungrab_pointer (guint32 time); + +void +gdk_input_init(void) +{ + gdk_input_vtable.set_mode = gdk_input_xfree_set_mode; + gdk_input_vtable.set_axes = gdk_input_common_set_axes; + gdk_input_vtable.motion_events = gdk_input_common_motion_events; + gdk_input_vtable.get_pointer = gdk_input_common_get_pointer; + gdk_input_vtable.grab_pointer = gdk_input_xfree_grab_pointer; + gdk_input_vtable.ungrab_pointer = gdk_input_xfree_ungrab_pointer; + gdk_input_vtable.configure_event = gdk_input_xfree_configure_event; + gdk_input_vtable.enter_event = gdk_input_xfree_enter_event; + gdk_input_vtable.other_event = gdk_input_xfree_other_event; + gdk_input_vtable.window_none_event = NULL; + gdk_input_vtable.enable_window = gdk_input_xfree_enable_window; + gdk_input_vtable.disable_window = gdk_input_xfree_disable_window; + + gdk_input_ignore_core = FALSE; + gdk_input_common_init(FALSE); +} + +static gint +gdk_input_xfree_set_mode (guint32 deviceid, GdkInputMode mode) +{ + GList *tmp_list; + GdkDevicePrivate *gdkdev; + GdkInputMode old_mode; + GdkInputWindow *input_window; + + gdkdev = gdk_input_find_device(deviceid); + g_return_val_if_fail (gdkdev != NULL,FALSE); + old_mode = gdkdev->info.mode; + + if (gdkdev->info.mode == mode) + return TRUE; + + gdkdev->info.mode = mode; + + if (mode == GDK_MODE_WINDOW) + { + gdkdev->info.has_cursor = FALSE; + for (tmp_list = gdk_input_windows; tmp_list; tmp_list = tmp_list->next) + { + input_window = (GdkInputWindow *)tmp_list->data; + if (input_window->mode != GDK_EXTENSION_EVENTS_CURSOR) + gdk_input_enable_window (input_window->window, gdkdev); + else + if (old_mode != GDK_MODE_DISABLED) + gdk_input_disable_window (input_window->window, gdkdev); + } + } + else if (mode == GDK_MODE_SCREEN) + { + gdkdev->info.has_cursor = TRUE; + for (tmp_list = gdk_input_windows; tmp_list; tmp_list = tmp_list->next) + gdk_input_enable_window (((GdkInputWindow *)tmp_list->data)->window, + gdkdev); + } + else /* mode == GDK_MODE_DISABLED */ + { + for (tmp_list = gdk_input_windows; tmp_list; tmp_list = tmp_list->next) + { + input_window = (GdkInputWindow *)tmp_list->data; + if (old_mode != GDK_MODE_WINDOW || + input_window->mode != GDK_EXTENSION_EVENTS_CURSOR) + gdk_input_disable_window (input_window->window, gdkdev); + } + } + + return TRUE; + +} + +static void +gdk_input_check_proximity() +{ + gint new_proximity = 0; + GList *tmp_list = gdk_input_devices; + + while (tmp_list && !new_proximity) + { + GdkDevicePrivate *gdkdev = (GdkDevicePrivate *)(tmp_list->data); + + if (gdkdev->info.mode != GDK_MODE_DISABLED + && gdkdev->info.deviceid != GDK_CORE_POINTER + && gdkdev->xdevice) + { + XDeviceState *state = XQueryDeviceState(GDK_DISPLAY(), + gdkdev->xdevice); + XInputClass *xic; + int i; + + xic = state->data; + for (i=0; i<state->num_classes; i++) + { + if (xic->class == ValuatorClass) + { + XValuatorState *xvs = (XValuatorState *)xic; + if ((xvs->mode & ProximityState) == InProximity) + { + new_proximity = TRUE; + } + break; + } + xic = (XInputClass *)((char *)xic + xic->length); + } + } + tmp_list = tmp_list->next; + } + + gdk_input_ignore_core = new_proximity; +} + +static void +gdk_input_xfree_configure_event (XConfigureEvent *xevent, GdkWindow *window) +{ + GdkInputWindow *input_window; + gint root_x, root_y; + + input_window = gdk_input_window_find(window); + g_return_if_fail (window != NULL); + + gdk_input_get_root_relative_geometry(GDK_DISPLAY(),GDK_WINDOW_XWINDOW(window), + &root_x, + &root_y, NULL, NULL); + + input_window->root_x = root_x; + input_window->root_y = root_y; +} + +static void +gdk_input_xfree_enter_event (XCrossingEvent *xevent, + GdkWindow *window) +{ + GdkInputWindow *input_window; + gint root_x, root_y; + + input_window = gdk_input_window_find(window); + g_return_if_fail (window != NULL); + + gdk_input_check_proximity(); + + gdk_input_get_root_relative_geometry(GDK_DISPLAY(),GDK_WINDOW_XWINDOW(window), + &root_x, + &root_y, NULL, NULL); + + input_window->root_x = root_x; + input_window->root_y = root_y; +} + +static gint +gdk_input_xfree_other_event (GdkEvent *event, + XEvent *xevent, + GdkWindow *window) +{ + GdkInputWindow *input_window; + + GdkDevicePrivate *gdkdev; + gint return_val; + + input_window = gdk_input_window_find(window); + g_return_val_if_fail (window != NULL, -1); + + /* This is a sort of a hack, as there isn't any XDeviceAnyEvent - + but it's potentially faster than scanning through the types of + every device. If we were deceived, then it won't match any of + the types for the device anyways */ + gdkdev = gdk_input_find_device(((XDeviceButtonEvent *)xevent)->deviceid); + + if (!gdkdev) { + return -1; /* we don't handle it - not an XInput event */ + } + + /* FIXME: It would be nice if we could just get rid of the events + entirely, instead of having to ignore them */ + if (gdkdev->info.mode == GDK_MODE_DISABLED || + (gdkdev->info.mode == GDK_MODE_WINDOW + && input_window->mode == GDK_EXTENSION_EVENTS_CURSOR)) + return FALSE; + + if (!gdk_input_ignore_core) + gdk_input_check_proximity(); + + return_val = gdk_input_common_other_event (event, xevent, + input_window, gdkdev); + + if (return_val > 0 && event->type == GDK_PROXIMITY_OUT && + gdk_input_ignore_core) + gdk_input_check_proximity(); + + /* Do a passive button grab. We have to be careful not to release + an explicit grab, if any. Doubling the grab should be harmless, + but we check anyways. */ + + /* FIXME, finding the proper events here is going to be SLOW - but + we might have different sets for each window/device combination */ + + if (return_val> 0 && !input_window->grabbed) + { + if (event->type == GDK_BUTTON_PRESS) + { + XEventClass event_classes[6]; + gint num_classes; + + gdk_input_common_find_events (window, gdkdev, + ((GdkWindowPrivate *)window)->extension_events, + event_classes, &num_classes); + + XGrabDevice( GDK_DISPLAY(), gdkdev->xdevice, + GDK_WINDOW_XWINDOW (window), + TRUE, num_classes, event_classes, + GrabModeAsync, GrabModeAsync, event->button.time); + } + else if (event->type == GDK_BUTTON_RELEASE) + XUngrabDevice( GDK_DISPLAY(), gdkdev->xdevice, event->button.time); + } + + return return_val; +} + +static gint +gdk_input_xfree_enable_window(GdkWindow *window, GdkDevicePrivate *gdkdev) +{ + /* FIXME: watchout, gdkdev might be core pointer, never opened */ + gdk_input_common_select_events (window, gdkdev); + return TRUE; +} + +static gint +gdk_input_xfree_disable_window(GdkWindow *window, GdkDevicePrivate *gdkdev) +{ + gdk_input_common_select_events (window, gdkdev); + return TRUE; +} + +static gint +gdk_input_xfree_grab_pointer (GdkWindow * window, + gint owner_events, + GdkEventMask event_mask, + GdkWindow * confine_to, + guint32 time) +{ + GdkInputWindow *input_window, *new_window; + GdkDevicePrivate *gdkdev; + GList *tmp_list; + XEventClass event_classes[6]; + gint num_classes; + + tmp_list = gdk_input_windows; + new_window = NULL; + while (tmp_list) + { + input_window = (GdkInputWindow *)tmp_list->data; + if (input_window->grabbed) + return AlreadyGrabbed; + + if (input_window->window == window) + { + new_window = input_window; + break; + } + + tmp_list = tmp_list->next; + } + + g_return_if_fail (new_window == NULL); + + new_window->grabbed = TRUE; + + tmp_list = gdk_input_devices; + while (tmp_list) + { + gdkdev = (GdkDevicePrivate *)tmp_list->data; + if (gdkdev->info.deviceid != GDK_CORE_POINTER && + gdkdev->xdevice && !gdkdev->button_state) + { + gdk_input_common_find_events (window, gdkdev, + ((GdkWindowPrivate *)window)->extension_events, + event_classes, &num_classes); + + /* FIXME: we should do something on failure */ + XGrabDevice( GDK_DISPLAY(), gdkdev->xdevice, + GDK_WINDOW_XWINDOW (window), + TRUE, num_classes, event_classes, + GrabModeAsync, GrabModeAsync, time); + } + tmp_list = tmp_list->next; + } + + return Success; +} + +static void +gdk_input_xfree_ungrab_pointer (guint32 time) +{ + GdkInputWindow *input_window; + GdkDevicePrivate *gdkdev; + GList *tmp_list; + + tmp_list = gdk_input_windows; + while (tmp_list) + { + input_window = (GdkInputWindow *)tmp_list->data; + if (input_window->grabbed) + break; + tmp_list = tmp_list->next; + } + + if (tmp_list) /* we found a grabbed window */ + { + input_window->grabbed = FALSE; + + tmp_list = gdk_input_devices; + while (tmp_list) + { + gdkdev = (GdkDevicePrivate *)tmp_list->data; + if (gdkdev->info.deviceid != GDK_CORE_POINTER && + gdkdev->xdevice && !gdkdev->button_state) + { + XUngrabDevice( gdk_display, gdkdev->xdevice, time); + } + tmp_list = tmp_list->next; + } + } +} + +#endif /* XINPUT_XFREE */ diff --git a/gdk/gdkpixmap.c b/gdk/gdkpixmap.c new file mode 100644 index 000000000..d2d96b6da --- /dev/null +++ b/gdk/gdkpixmap.c @@ -0,0 +1,657 @@ +/* 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 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include "../config.h" +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <X11/Xlib.h> + +#include "gdk.h" +#include "gdkprivate.h" + +typedef struct +{ + gchar *color_string; + GdkColor color; + gint transparent; +} _GdkPixmapColor; + +GdkPixmap* +gdk_pixmap_new (GdkWindow *window, + gint width, + gint height, + gint depth) +{ + GdkPixmap *pixmap; + GdkWindowPrivate *private; + GdkWindowPrivate *window_private; + + if (!window) + window = (GdkWindow*) &gdk_root_parent; + + if (depth == -1) + gdk_window_get_geometry (window, NULL, NULL, NULL, NULL, &depth); + + private = g_new (GdkWindowPrivate, 1); + pixmap = (GdkPixmap*) private; + + window_private = (GdkWindowPrivate*) window; + + private->xdisplay = window_private->xdisplay; + private->window_type = GDK_WINDOW_PIXMAP; + private->xwindow = XCreatePixmap (private->xdisplay, window_private->xwindow, + width, height, depth); + private->parent = NULL; + private->x = 0; + private->y = 0; + private->width = width; + private->height = height; + private->resize_count = 0; + private->ref_count = 1; + private->destroyed = 0; + + gdk_xid_table_insert (&private->xwindow, pixmap); + + return pixmap; +} + +GdkPixmap * +gdk_bitmap_create_from_data (GdkWindow *window, + gchar *data, + gint width, + gint height) +{ + GdkPixmap *pixmap; + GdkWindowPrivate *private; + GdkWindowPrivate *window_private; + + g_return_val_if_fail (data != NULL, NULL); + + if (!window) + window = (GdkWindow*) &gdk_root_parent; + + private = g_new (GdkWindowPrivate, 1); + pixmap = (GdkPixmap*) private; + + window_private = (GdkWindowPrivate*) window; + + private->parent = NULL; + private->xdisplay = window_private->xdisplay; + private->window_type = GDK_WINDOW_PIXMAP; + private->x = 0; + private->y = 0; + private->width = width; + private->height = height; + private->resize_count = 0; + private->ref_count = 1; + private->destroyed = FALSE; + + private->xwindow = XCreateBitmapFromData (private->xdisplay, + window_private->xwindow, + data, width, height); + + gdk_xid_table_insert (&private->xwindow, pixmap); + + return pixmap; +} + +GdkPixmap* +gdk_pixmap_create_from_data (GdkWindow *window, + gchar *data, + gint width, + gint height, + gint depth, + GdkColor *fg, + GdkColor *bg) +{ + GdkPixmap *pixmap; + GdkWindowPrivate *private; + GdkWindowPrivate *window_private; + + g_return_val_if_fail (data != NULL, NULL); + g_return_val_if_fail (fg != NULL, NULL); + g_return_val_if_fail (bg != NULL, NULL); + + if (!window) + window = (GdkWindow*) &gdk_root_parent; + + if (depth == -1) + gdk_window_get_geometry (window, NULL, NULL, NULL, NULL, &depth); + + private = g_new (GdkWindowPrivate, 1); + pixmap = (GdkPixmap*) private; + + window_private = (GdkWindowPrivate*) window; + + private->parent = NULL; + private->xdisplay = window_private->xdisplay; + private->window_type = GDK_WINDOW_PIXMAP; + private->x = 0; + private->y = 0; + private->width = width; + private->height = height; + private->resize_count = 0; + private->ref_count = 1; + private->destroyed = FALSE; + + private->xwindow = XCreatePixmapFromBitmapData (private->xdisplay, + window_private->xwindow, + data, width, height, + fg->pixel, bg->pixel, depth); + + gdk_xid_table_insert (&private->xwindow, pixmap); + + return pixmap; +} + +gint +gdk_pixmap_seek_string (FILE *infile, + const gchar *str, + gint skip_comments) +{ + char instr[1024]; + + while (!feof (infile)) + { + fscanf (infile, "%s", instr); + if (skip_comments == TRUE && strcmp (instr, "/*") == 0) + { + fscanf (infile, "%s", instr); + while (!feof (infile) && strcmp (instr, "*/") != 0) + fscanf (infile, "%s", instr); + fscanf(infile, "%s", instr); + } + if (strcmp (instr, str)==0) + return TRUE; + } + + return FALSE; +} + +gint +gdk_pixmap_seek_char (FILE *infile, + gchar c) +{ + gchar b, oldb; + + while (!feof (infile)) + { + fscanf(infile, "%c", &b); + if (c != b && b == '/') + { + fscanf (infile, "%c", &b); + if (b == '*') + { + oldb = b; + while (!feof (infile) && !(oldb == '*' && b == '/')) + { + oldb = b; + fscanf (infile, "%c", &b); + } + fscanf (infile, "%c", &b); + } + } + if (c == b) + return TRUE; + } + + return FALSE; +} + +gint +gdk_pixmap_read_string (FILE *infile, + gchar **buffer, + int *buffer_size) +{ + gchar c; + gint cnt = 0; + + if ((*buffer) == NULL) + { + (*buffer_size) = 10 * sizeof (gchar); + (*buffer) = (gchar *) malloc (*buffer_size); + } + + do + fscanf (infile, "%c", &c); + while (!feof (infile) && c != '"'); + + if (c != '"') + return FALSE; + + while (!feof (infile)) + { + fscanf (infile, "%c", &c); + + if (cnt == (*buffer_size)) + { + (*buffer_size) *= 2; + (*buffer) = (gchar *) realloc ((*buffer), *buffer_size); + } + + if (c != '"') + (*buffer)[cnt++] = c; + else + { + (*buffer)[cnt++] = 0; + return TRUE; + } + } + + return FALSE; +} + +gchar* +gdk_pixmap_skip_whitespaces (gchar *buffer) +{ + gint32 index = 0; + + while (buffer[index] != 0 && (buffer[index] == 0x20 || buffer[index] == 0x09)) + index++; + + return &buffer[index]; +} + +gchar* +gdk_pixmap_skip_string (gchar *buffer) +{ + gint32 index = 0; + + while (buffer[index] != 0 && buffer[index] != 0x20 && buffer[index] != 0x09) + index++; + + return &buffer[index]; +} + +gchar* +gdk_pixmap_extract_color (gchar *buffer) +{ + gint counter, finished = FALSE, numnames; + gchar *ptr = NULL, ch, temp[128]; + gchar color[128], *retcol; + + counter = 0; + while (ptr == NULL) + { + if (buffer[counter] == 'c') + { + ch = buffer[counter + 1]; + if (ch == 0x20 || ch == 0x09) + ptr = &buffer[counter + 1]; + } + else if (buffer[counter] == 0) + return NULL; + + counter++; + } + + if (ptr == NULL) + return NULL; + + ptr = gdk_pixmap_skip_whitespaces (ptr); + + if (ptr[0] == 0) + return NULL; + else if (ptr[0] == '#') + { + retcol = g_new(gchar, strlen (ptr) + 1); + strcpy (retcol, ptr); + return retcol; + } + + color[0] = 0; + numnames = 0; + + while (finished == FALSE) + { + sscanf (ptr, "%s", temp); + + if ((gint)ptr[0] == 0 || strcmp ("s", temp) == 0 || strcmp ("m", temp) == 0 || + strcmp ("g", temp) == 0 || strcmp ("g4", temp) == 0) + finished = TRUE; + else + { + if (numnames > 0) + strcat (color, " "); + strcat (color, temp); + ptr = gdk_pixmap_skip_string (ptr); + ptr = gdk_pixmap_skip_whitespaces (ptr); + numnames++; + } + } + + retcol = g_new(gchar, strlen (color) + 1); + strcpy (retcol, color); + return retcol; +} + + +GdkPixmap* +gdk_pixmap_create_from_xpm (GdkWindow *window, + GdkBitmap **mask, + GdkColor *transparent_color, + const gchar *filename) +{ + FILE *infile = NULL; + GdkPixmap *pixmap = NULL; + GdkImage *image = NULL; + GdkColormap *colormap; + GdkVisual *visual; + GdkGC *gc; + GdkColor tmp_color; + gint width, height, num_cols, cpp, cnt, n, ns, xcnt, ycnt; + gchar *buffer = NULL, *color_name = NULL, pixel_str[32]; + guint buffer_size = 0; + _GdkPixmapColor *colors = NULL, *color = NULL; + gulong index; + + if (!window) + window = (GdkWindow*) &gdk_root_parent; + + infile = fopen (filename, "rb"); + if (infile != NULL) + { + if (gdk_pixmap_seek_string (infile, "XPM", FALSE) == TRUE) + { + if (gdk_pixmap_seek_char (infile,'{') == TRUE) + { + gdk_pixmap_seek_char (infile, '"'); + fseek (infile, -1, SEEK_CUR); + gdk_pixmap_read_string (infile, &buffer, &buffer_size); + + sscanf (buffer,"%d %d %d %d", &width, &height, &num_cols, &cpp); + + colors = g_new(_GdkPixmapColor, num_cols); + + colormap = gdk_window_get_colormap (window); + visual = gdk_window_get_visual (window); + + if (transparent_color == NULL) + { + gdk_color_white (colormap, &tmp_color); + transparent_color = &tmp_color; + } + + for (cnt = 0; cnt < num_cols; cnt++) + { + gdk_pixmap_seek_char (infile, '"'); + fseek (infile, -1, SEEK_CUR); + gdk_pixmap_read_string (infile, &buffer, &buffer_size); + + colors[cnt].color_string = g_new(gchar, cpp + 1); + for (n = 0; n < cpp; n++) + colors[cnt].color_string[n] = buffer[n]; + colors[cnt].color_string[n] = 0; + colors[cnt].transparent = FALSE; + + if (color_name != NULL) + g_free (color_name); + + color_name = gdk_pixmap_extract_color (&buffer[cpp]); + + if (color_name != NULL) + { + if (gdk_color_parse (color_name, &colors[cnt].color) == FALSE) + { + colors[cnt].color = *transparent_color; + colors[cnt].transparent = TRUE; + } + } + else + { + colors[cnt].color = *transparent_color; + colors[cnt].transparent = TRUE; + } + + gdk_color_alloc (colormap, &colors[cnt].color); + } + + index = 0; + image = gdk_image_new (GDK_IMAGE_FASTEST, visual, width, height); + + gc = NULL; + if (mask) + { + *mask = gdk_pixmap_new (window, width, height, 1); + gc = gdk_gc_new (*mask); + + gdk_color_black (colormap, &tmp_color); + gdk_gc_set_foreground (gc, &tmp_color); + gdk_draw_rectangle (*mask, gc, TRUE, 0, 0, -1, -1); + + gdk_color_white (colormap, &tmp_color); + gdk_gc_set_foreground (gc, &tmp_color); + } + + for (ycnt = 0; ycnt < height; ycnt++) + { + gdk_pixmap_read_string (infile, &buffer, &buffer_size); + + for (n = 0, cnt = 0, xcnt = 0; n < (width * cpp); n += cpp, xcnt++) + { + strncpy (pixel_str, &buffer[n], cpp); + pixel_str[cpp] = 0; + color = NULL; + ns = 0; + + while (color == NULL) + { + if (strcmp (pixel_str, colors[ns].color_string) == 0) + color = &colors[ns]; + else + ns++; + } + + gdk_image_put_pixel (image, xcnt, ycnt, color->color.pixel); + + if (mask && color->transparent) + { + if (cnt < xcnt) + gdk_draw_line (*mask, gc, cnt, ycnt, xcnt - 1, ycnt); + cnt = xcnt + 1; + } + } + + if (mask && (cnt < xcnt)) + gdk_draw_line (*mask, gc, cnt, ycnt, xcnt - 1, ycnt); + } + + if (mask) + gdk_gc_destroy (gc); + + pixmap = gdk_pixmap_new (window, width, height, visual->depth); + + gc = gdk_gc_new (pixmap); + gdk_gc_set_foreground (gc, transparent_color); + gdk_draw_image (pixmap, gc, image, 0, 0, 0, 0, image->width, image->height); + gdk_gc_destroy (gc); + gdk_image_destroy (image); + } + } + + fclose (infile); + free (buffer); + + if (colors != NULL) + { + for (cnt = 0; cnt < num_cols; cnt++) + g_free (colors[cnt].color_string); + g_free (colors); + } + } + + return pixmap; +} + +GdkPixmap* +gdk_pixmap_create_from_xpm_d (GdkWindow *window, + GdkBitmap **mask, + GdkColor *transparent_color, + gchar **data) +{ + GdkPixmap *pixmap = NULL; + GdkImage *image = NULL; + GdkColormap *colormap; + GdkVisual *visual; + GdkGC *gc; + GdkColor tmp_color; + gint width, height, num_cols, cpp, cnt, n, ns, xcnt, ycnt, i; + gchar *buffer, *color_name = NULL, pixel_str[32]; + _GdkPixmapColor *colors = NULL, *color = NULL; + gulong index; + + if (!window) + window = (GdkWindow*) &gdk_root_parent; + + i = 0; + buffer = data[i++]; + sscanf (buffer,"%d %d %d %d", &width, &height, &num_cols, &cpp); + + colors = g_new(_GdkPixmapColor, num_cols); + + colormap = gdk_window_get_colormap (window); + visual = gdk_window_get_visual (window); + + if (transparent_color == NULL) + { + gdk_color_white (colormap, &tmp_color); + transparent_color = &tmp_color; + } + + for (cnt = 0; cnt < num_cols; cnt++) + { + buffer = data[i++]; + + colors[cnt].color_string = g_new(gchar, cpp + 1); + for (n = 0; n < cpp; n++) + colors[cnt].color_string[n] = buffer[n]; + colors[cnt].color_string[n] = 0; + colors[cnt].transparent = FALSE; + + if (color_name != NULL) + g_free (color_name); + + color_name = gdk_pixmap_extract_color (&buffer[cpp]); + + if (color_name != NULL) + { + if (gdk_color_parse (color_name, &colors[cnt].color) == FALSE) + { + colors[cnt].color = *transparent_color; + colors[cnt].transparent = TRUE; + } + } + else + { + colors[cnt].color = *transparent_color; + colors[cnt].transparent = TRUE; + } + + gdk_color_alloc (colormap, &colors[cnt].color); + } + + index = 0; + image = gdk_image_new (GDK_IMAGE_FASTEST, visual, width, height); + + gc = NULL; + if (mask) + { + *mask = gdk_pixmap_new (window, width, height, 1); + gc = gdk_gc_new (*mask); + + gdk_color_black (colormap, &tmp_color); + gdk_gc_set_foreground (gc, &tmp_color); + gdk_draw_rectangle (*mask, gc, TRUE, 0, 0, -1, -1); + + gdk_color_white (colormap, &tmp_color); + gdk_gc_set_foreground (gc, &tmp_color); + } + + for (ycnt = 0; ycnt < height; ycnt++) + { + buffer = data[i++]; + + for (n = 0, cnt = 0, xcnt = 0; n < (width * cpp); n += cpp, xcnt++) + { + strncpy (pixel_str, &buffer[n], cpp); + pixel_str[cpp] = 0; + color = NULL; + ns = 0; + + while (color == NULL) + { + if (strcmp (pixel_str, colors[ns].color_string) == 0) + color = &colors[ns]; + else + ns++; + } + + gdk_image_put_pixel (image, xcnt, ycnt, color->color.pixel); + + if (mask && color->transparent) + { + if (cnt < xcnt) + gdk_draw_line (*mask, gc, cnt, ycnt, xcnt - 1, ycnt); + cnt = xcnt + 1; + } + } + + if (mask && (cnt < xcnt)) + gdk_draw_line (*mask, gc, cnt, ycnt, xcnt - 1, ycnt); + } + + if (mask) + gdk_gc_destroy (gc); + + pixmap = gdk_pixmap_new (window, width, height, visual->depth); + + gc = gdk_gc_new (pixmap); + gdk_gc_set_foreground (gc, transparent_color); + gdk_draw_image (pixmap, gc, image, 0, 0, 0, 0, image->width, image->height); + gdk_gc_destroy (gc); + gdk_image_destroy (image); + + if (colors != NULL) + { + for (cnt = 0; cnt < num_cols; cnt++) + g_free (colors[cnt].color_string); + g_free (colors); + } + + return pixmap; +} + +void +gdk_pixmap_destroy (GdkPixmap *pixmap) +{ + GdkWindowPrivate *private; + + g_return_if_fail (pixmap != NULL); + + private = (GdkPixmapPrivate*) pixmap; + if (private->ref_count <= 0) + { + XFreePixmap (private->xdisplay, private->xwindow); + gdk_xid_table_remove (private->xwindow); + g_free (pixmap); + } + else + { + private->ref_count -= 1; + } +} diff --git a/gdk/gdkprivate.h b/gdk/gdkprivate.h new file mode 100644 index 000000000..3c1677e41 --- /dev/null +++ b/gdk/gdkprivate.h @@ -0,0 +1,197 @@ +/* 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 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef __GDK_PRIVATE_H__ +#define __GDK_PRIVATE_H__ + + +#include <X11/Xlib.h> +#include <X11/Xutil.h> +#include <gdk/gdktypes.h> + +#define DND_PROTOCOL_VERSION 0 + +#define gdk_window_lookup(xid) ((GdkWindow*) gdk_xid_table_lookup (xid)) +#define gdk_pixmap_lookup(xid) ((GdkPixmap*) gdk_xid_table_lookup (xid)) +#define gdk_font_lookup(xid) ((GdkFont*) gdk_xid_table_lookup (xid)) + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +typedef struct _GdkWindowPrivate GdkWindowPrivate; +typedef struct _GdkWindowPrivate GdkPixmapPrivate; +typedef struct _GdkImagePrivate GdkImagePrivate; +typedef struct _GdkGCPrivate GdkGCPrivate; +typedef struct _GdkColormapPrivate GdkColormapPrivate; +typedef struct _GdkVisualPrivate GdkVisualPrivate; +typedef struct _GdkFontPrivate GdkFontPrivate; +typedef struct _GdkCursorPrivate GdkCursorPrivate; + + +struct _GdkWindowPrivate +{ + GdkWindow window; + GdkWindow *parent; + Window xwindow; + Display *xdisplay; + gint16 x; + gint16 y; + guint16 width; + guint16 height; + guint8 resize_count; + guint8 ref_count; + guint8 window_type; + guint8 destroyed : 2; + guint8 dnd_drag_enabled : 1, + dnd_drag_datashow : 1, + dnd_drag_destructive_op : 1, + dnd_drag_accepted : 1, + dnd_drop_enabled : 1, + dnd_drop_destructive_op : 1; + GdkAtom dnd_drag_data_type, *dnd_drag_data_typesavail; + guint dnd_drag_data_numtypesavail; + /* We have to turn on MotionMask/EnterWindowMask/LeaveWindowMask + during drags, then set it back to what it was after */ + glong dnd_drag_savedeventmask, dnd_drag_eventmask; + GdkAtom *dnd_drop_data_typesavail; + guint dnd_drop_data_numtypesavail; + /* need to allow custom drag/drop cursors */ + + gint extension_events; +}; + +struct _GdkImagePrivate +{ + GdkImage image; + XImage *ximage; + Display *xdisplay; + gpointer x_shm_info; + + void (*image_put) (GdkDrawable *window, + GdkGC *gc, + GdkImage *image, + gint xsrc, + gint ysrc, + gint xdest, + gint ydest, + gint width, + gint height); +}; + +struct _GdkGCPrivate +{ + GdkGC gc; + GC xgc; + Display *xdisplay; +}; + +struct _GdkColormapPrivate +{ + GdkColormap colormap; + Colormap xcolormap; + Display *xdisplay; + GdkVisual *visual; + gint private_val; + gint next_color; + gint ref_count; +}; + +struct _GdkVisualPrivate +{ + GdkVisual visual; + Visual *xvisual; +}; + +struct _GdkFontPrivate +{ + GdkFont font; + /* XFontStruct *xfont; */ + /* generic pointer point to XFontStruct or XFontSet */ + gpointer xfont; + Display *xdisplay; + gint ref_count; +}; + +struct _GdkCursorPrivate +{ + GdkCursor cursor; + Cursor xcursor; + Display *xdisplay; +}; + +struct _GdkDndGlobals { + GdkAtom gdk_XdeEnter, gdk_XdeLeave, gdk_XdeRequest; + GdkAtom gdk_XdeDataAvailable, gdk_XdeDataShow, gdk_XdeCancel; + GdkAtom gdk_XdeTypelist; + Cursor gdk_cursor_dragdefault, gdk_cursor_dragok; + GdkWindow **drag_startwindows; + guint drag_numwindows; + guint8 drag_really; + GdkPoint drag_dropcoords; +}; +typedef struct _GdkDndGlobals GdkDndGlobals; + +void gdk_window_init (void); +void gdk_visual_init (void); + +void gdk_image_init (void); +void gdk_image_exit (void); + +GdkColormap* gdk_colormap_lookup (Colormap xcolormap); +GdkVisual* gdk_visual_lookup (Visual *xvisual); + +void gdk_window_real_destroy (GdkWindow *window); +void gdk_window_add_colormap_windows (GdkWindow *window); + +void gdk_xid_table_insert (XID *xid, + gpointer data); +void gdk_xid_table_remove (XID xid); +gpointer gdk_xid_table_lookup (XID xid); + + +extern gint gdk_debug_level; +extern gint gdk_show_events; +extern gint gdk_use_xshm; +extern gint gdk_stack_trace; +extern gchar *gdk_display_name; +extern Display *gdk_display; +extern gint gdk_screen; +extern Window gdk_root_window; +extern Window gdk_leader_window; +extern GdkWindowPrivate gdk_root_parent; +extern Atom gdk_wm_delete_window; +extern Atom gdk_wm_take_focus; +extern Atom gdk_wm_protocols; +extern Atom gdk_wm_window_protocols[]; +extern Atom gdk_selection_property; +extern GdkDndGlobals gdk_dnd; +extern GdkWindow *selection_owner[]; +extern gchar *gdk_progname; +extern gchar *gdk_progclass; +extern gint gdk_error_code; +extern gint gdk_error_warnings; + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GDK_PRIVATE_H__ */ diff --git a/gdk/gdkproperty.c b/gdk/gdkproperty.c new file mode 100644 index 000000000..35d8a50cf --- /dev/null +++ b/gdk/gdkproperty.c @@ -0,0 +1,194 @@ +/* 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 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include <X11/Xlib.h> +#include <X11/Xatom.h> +#include <string.h> +#include "gdk.h" +#include "gdkprivate.h" + + +GdkAtom +gdk_atom_intern (const gchar *atom_name, + gint only_if_exists) +{ + return XInternAtom (gdk_display, atom_name, only_if_exists); +} + +gchar * +gdk_atom_name (GdkAtom atom) +{ + gchar *t; + gchar *name; + + /* If this atom doesn't exist, we'll die with an X error unless + we take precautions */ + + gdk_error_warnings = 0; + t = XGetAtomName (gdk_display, atom); + gdk_error_warnings = 1; + + if (gdk_error_code == -1) + { + return NULL; + } + else + { + name = g_strdup (t); + XFree (t); + + return name; + } +} + +gint +gdk_property_get (GdkWindow *window, + GdkAtom property, + GdkAtom type, + gulong offset, + gulong length, + gint pdelete, + GdkAtom *actual_property_type, + gint *actual_format_type, + gint *actual_length, + guchar **data) +{ + GdkWindowPrivate *private; + Display *xdisplay; + Window xwindow; + Atom ret_prop_type; + gint ret_format; + gulong ret_nitems; + gulong ret_bytes_after; + gulong ret_length; + guchar *ret_data; + + if (window) + { + private = (GdkWindowPrivate*) window; + xdisplay = private->xdisplay; + xwindow = private->xwindow; + } + else + { + xdisplay = gdk_display; + xwindow = gdk_root_window; + } + + XGetWindowProperty (xdisplay, xwindow, property, + offset, (length + 3) / 4, pdelete, + type, &ret_prop_type, &ret_format, + &ret_nitems, &ret_bytes_after, + &ret_data); + + if ((ret_prop_type == None) && (ret_format == 0)) + return FALSE; + + if (actual_property_type) + *actual_property_type = ret_prop_type; + if (actual_format_type) + *actual_format_type = ret_format; + + if (ret_prop_type != property) + { + XFree (ret_data); + return FALSE; + } + + /* FIXME: ignoring bytes_after could have very bad effects */ + + if (data) + { + switch (ret_format) + { + case 8: + ret_length = ret_nitems; + break; + case 16: + ret_length = 2 * ret_nitems; + break; + case 32: + ret_length = 4 * ret_nitems; + break; + default: + g_warning ("unknown property return format: %d", ret_format); + XFree (ret_data); + return FALSE; + } + + *data = g_new (guchar, ret_length); + memcpy (*data, ret_data, ret_length); + if (actual_length) + *actual_length = ret_length; + } + + XFree (ret_data); + + return TRUE; +} + +void +gdk_property_change (GdkWindow *window, + GdkAtom property, + GdkAtom type, + gint format, + GdkPropMode mode, + guchar *data, + gint nelements) +{ + GdkWindowPrivate *private; + Display *xdisplay; + Window xwindow; + + if (window) + { + private = (GdkWindowPrivate*) window; + xdisplay = private->xdisplay; + xwindow = private->xwindow; + } + else + { + xdisplay = gdk_display; + xwindow = gdk_root_window; + } + + XChangeProperty (xdisplay, xwindow, property, type, + format, mode, data, nelements); +} + +void +gdk_property_delete (GdkWindow *window, + GdkAtom property) +{ + GdkWindowPrivate *private; + Display *xdisplay; + Window xwindow; + + if (window) + { + private = (GdkWindowPrivate*) window; + xdisplay = private->xdisplay; + xwindow = private->xwindow; + } + else + { + xdisplay = gdk_display; + xwindow = gdk_root_window; + } + + XDeleteProperty (xdisplay, xwindow, property); +} diff --git a/gdk/gdkrectangle.c b/gdk/gdkrectangle.c new file mode 100644 index 000000000..dbb35b664 --- /dev/null +++ b/gdk/gdkrectangle.c @@ -0,0 +1,83 @@ +/* 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 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include "gdk.h" + + +gint +gdk_rectangle_intersect (GdkRectangle *src1, + GdkRectangle *src2, + GdkRectangle *dest) +{ + GdkRectangle *temp; + gint src1_x2, src1_y2; + gint src2_x2, src2_y2; + gint return_val; + + g_return_val_if_fail (src1 != NULL, FALSE); + g_return_val_if_fail (src2 != NULL, FALSE); + g_return_val_if_fail (dest != NULL, FALSE); + + return_val = FALSE; + + if (src2->x < src1->x) + { + temp = src1; + src1 = src2; + src2 = temp; + } + dest->x = src2->x; + + src1_x2 = src1->x + src1->width; + src2_x2 = src2->x + src2->width; + + if (src2->x < src1_x2) + { + if (src1_x2 < src2_x2) + dest->width = src1_x2 - dest->x; + else + dest->width = src2_x2 - dest->x; + + if (src2->y < src1->y) + { + temp = src1; + src1 = src2; + src2 = temp; + } + dest->y = src2->y; + + src1_y2 = src1->y + src1->height; + src2_y2 = src2->y + src2->height; + + if (src2->y < src1_y2) + { + return_val = TRUE; + + if (src1_y2 < src2_y2) + dest->height = src1_y2 - dest->y; + else + dest->height = src2_y2 - dest->y; + + if (dest->height == 0) + return_val = FALSE; + if (dest->width == 0) + return_val = FALSE; + } + } + + return return_val; +} diff --git a/gdk/gdkselection.c b/gdk/gdkselection.c new file mode 100644 index 000000000..6bd425110 --- /dev/null +++ b/gdk/gdkselection.c @@ -0,0 +1,168 @@ +/* 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 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include <X11/Xlib.h> +#include <X11/Xatom.h> +#include <string.h> +#include "gdk.h" +#include "gdkprivate.h" + + +gint +gdk_selection_owner_set (GdkWindow *owner, + GdkAtom selection, + guint32 time, + gint send_event) +{ + GdkWindowPrivate *private; + Display *xdisplay; + Window xwindow; + + if (owner) + { + private = (GdkWindowPrivate*) owner; + xdisplay = private->xdisplay; + xwindow = private->xwindow; + } + else + { + xdisplay = gdk_display; + xwindow = None; + } + + XSetSelectionOwner (xdisplay, selection, xwindow, time); + + return (XGetSelectionOwner (xdisplay, selection) == xwindow); +} + +GdkWindow* +gdk_selection_owner_get (GdkAtom selection) +{ + Window xwindow; + + xwindow = XGetSelectionOwner (gdk_display, selection); + if (xwindow == None) + return NULL; + + return gdk_window_lookup (xwindow); +} + +void +gdk_selection_convert (GdkWindow *requestor, + GdkAtom selection, + GdkAtom target, + guint32 time) +{ + GdkWindowPrivate *private; + + g_return_if_fail (requestor != NULL); + + private = (GdkWindowPrivate*) requestor; + + XConvertSelection (private->xdisplay, selection, target, + gdk_selection_property, private->xwindow, time); +} + +gint +gdk_selection_property_get (GdkWindow *requestor, + guchar **data, + GdkAtom *ret_type, + gint *ret_format) +{ + GdkWindowPrivate *private; + gulong nitems; + gulong nbytes; + gulong length; + GdkAtom prop_type; + gint prop_format; + guchar *t; + + g_return_val_if_fail (requestor != NULL, 0); + + /* If retrieved chunks are typically small, (and the ICCM says the + should be) it would be a win to try first with a buffer of + moderate length, to avoid two round trips to the server */ + + private = (GdkWindowPrivate*) requestor; + + XGetWindowProperty (private->xdisplay, private->xwindow, + gdk_selection_property, 0, 0, False, + AnyPropertyType, &prop_type, &prop_format, + &nitems, &nbytes, &t); + + if (ret_type) + *ret_type = prop_type; + if (ret_format) + *ret_format = prop_format; + + if (prop_type == None) + { + *data = NULL; + return 0; + } + + XFree (t); + + /* Add on an extra byte to handle null termination. X guarantees + that t will be 1 longer than nbytes and null terminated */ + length = nbytes + 1; + + /* We can't delete the selection here, because it might be the INCR + protocol, in which case the client has to make sure they'll be + notified of PropertyChange events _before_ the property is deleted. + Otherwise there's no guarantee we'll win the race ... */ + XGetWindowProperty (private->xdisplay, private->xwindow, + gdk_selection_property, 0, (nbytes + 3) / 4, False, + AnyPropertyType, &prop_type, &prop_format, + &nitems, &nbytes, &t); + + if (prop_type != None) + { + *data = g_new (guchar, length); + memcpy (*data, t, length); + XFree (t); + return length-1; + } + else + { + *data = NULL; + return 0; + } +} + + +void +gdk_selection_send_notify (guint32 requestor, + GdkAtom selection, + GdkAtom target, + GdkAtom property, + guint32 time) +{ + XSelectionEvent xevent; + + xevent.type = SelectionNotify; + xevent.serial = 0; + xevent.send_event = True; + xevent.display = gdk_display; + xevent.requestor = requestor; + xevent.selection = selection; + xevent.target = target; + xevent.property = property; + xevent.time = time; + + XSendEvent (gdk_display, requestor, False, NoEventMask, (XEvent*) &xevent); +} diff --git a/gdk/gdktypes.h b/gdk/gdktypes.h new file mode 100644 index 000000000..7fc7434ac --- /dev/null +++ b/gdk/gdktypes.h @@ -0,0 +1,967 @@ +/* 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 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef __GDK_TYPES_H__ +#define __GDK_TYPES_H__ + + +/* GDK uses "glib". (And so does GTK). + */ +#include <glib.h> + + +#define GDK_NONE 0L +#define GDK_CURRENT_TIME 0L +#define GDK_PARENT_RELATIVE 1L + +/* special deviceid for core pointer events */ +#define GDK_CORE_POINTER 0xfedc + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +/* Type definitions for the basic structures. + */ + +typedef gulong GdkAtom; +typedef struct _GdkColor GdkColor; +typedef struct _GdkColormap GdkColormap; +typedef struct _GdkVisual GdkVisual; +typedef struct _GdkWindowAttr GdkWindowAttr; +typedef struct _GdkWindow GdkWindow; +typedef struct _GdkWindow GdkPixmap; +typedef struct _GdkWindow GdkBitmap; +typedef struct _GdkWindow GdkDrawable; +typedef struct _GdkImage GdkImage; +typedef struct _GdkGCValues GdkGCValues; +typedef struct _GdkGC GdkGC; +typedef struct _GdkPoint GdkPoint; +typedef struct _GdkRectangle GdkRectangle; +typedef struct _GdkSegment GdkSegment; +typedef struct _GdkFont GdkFont; +typedef struct _GdkCursor GdkCursor; + +typedef struct _GdkEventAny GdkEventAny; +typedef struct _GdkEventExpose GdkEventExpose; +typedef struct _GdkEventMotion GdkEventMotion; +typedef struct _GdkEventButton GdkEventButton; +typedef struct _GdkEventKey GdkEventKey; +typedef struct _GdkEventFocus GdkEventFocus; +typedef struct _GdkEventCrossing GdkEventCrossing; +typedef struct _GdkEventConfigure GdkEventConfigure; +typedef struct _GdkEventProperty GdkEventProperty; +typedef struct _GdkEventSelection GdkEventSelection; +typedef struct _GdkEventProximity GdkEventProximity; +typedef struct _GdkEventOther GdkEventOther; +typedef struct _GdkEventDragBegin GdkEventDragBegin; +typedef struct _GdkEventDragRequest GdkEventDragRequest; +typedef struct _GdkEventDropEnter GdkEventDropEnter; +typedef struct _GdkEventDropDataAvailable GdkEventDropDataAvailable; +typedef struct _GdkEventDropLeave GdkEventDropLeave; +typedef struct _GdkEventClient GdkEventClient; +typedef union _GdkEvent GdkEvent; +typedef struct _GdkDeviceInfo GdkDeviceInfo; +typedef struct _GdkTimeCoord GdkTimeCoord; +typedef gint (*GdkEventFunc) (GdkEvent *event, + gpointer data); + + +/* Types of windows. + * Root: There is only 1 root window and it is initialized + * at startup. Creating a window of type GDK_WINDOW_ROOT + * is an error. + * Toplevel: Windows which interact with the window manager. + * Child: Windows which are children of some other type of window. + * (Any other type of window). Most windows are child windows. + * Dialog: A special kind of toplevel window which interacts with + * the window manager slightly differently than a regular + * toplevel window. Dialog windows should be used for any + * transient window. + * Pixmap: Pixmaps are really just another kind of window which + * doesn't actually appear on the screen. It can't have + * children, either and is really just a convenience so + * that the drawing functions can work on both windows + * and pixmaps transparently. (ie. You shouldn't pass a + * pixmap to any procedure which accepts a window with the + * exception of the drawing functions). + */ +typedef enum +{ + GDK_WINDOW_ROOT, + GDK_WINDOW_TOPLEVEL, + GDK_WINDOW_CHILD, + GDK_WINDOW_DIALOG, + GDK_WINDOW_TEMP, + GDK_WINDOW_PIXMAP +} GdkWindowType; + +/* Classes of windows. + * InputOutput: Almost every window should be of this type. Such windows + * receive events and are also displayed on screen. + * InputOnly: Used only in special circumstances when events need to be + * stolen from another window or windows. Input only windows + * have no visible output, so they are handy for placing over + * top of a group of windows in order to grab the events (or + * filter the events) from those windows. + */ +typedef enum +{ + GDK_INPUT_OUTPUT, + GDK_INPUT_ONLY +} GdkWindowClass; + +/* Types of images. + * Normal: Normal X image type. These are slow as they involve passing + * the entire image through the X connection each time a draw + * request is required. + * Shared: Shared memory X image type. These are fast as the X server + * and the program actually use the same piece of memory. They + * should be used with care though as there is the possibility + * for both the X server and the program to be reading/writing + * the image simultaneously and producing undesired results. + */ +typedef enum +{ + GDK_IMAGE_NORMAL, + GDK_IMAGE_SHARED, + GDK_IMAGE_FASTEST +} GdkImageType; + +/* Types of visuals. + * StaticGray: + * Grayscale: + * StaticColor: + * PseudoColor: + * TrueColor: + * DirectColor: + */ +typedef enum +{ + GDK_VISUAL_STATIC_GRAY, + GDK_VISUAL_GRAYSCALE, + GDK_VISUAL_STATIC_COLOR, + GDK_VISUAL_PSEUDO_COLOR, + GDK_VISUAL_TRUE_COLOR, + GDK_VISUAL_DIRECT_COLOR +} GdkVisualType; + +/* Types of font. + * GDK_FONT_FONT: the font is an XFontStruct. + * GDK_FONT_FONTSET: the font is an XFontSet used for I18N. + */ +typedef enum +{ + GDK_FONT_FONT, + GDK_FONT_FONTSET +} GdkFontType; + +/* Window attribute mask values. + * GDK_WA_TITLE: The "title" field is valid. + * GDK_WA_X: The "x" field is valid. + * GDK_WA_Y: The "y" field is valid. + * GDK_WA_CURSOR: The "cursor" field is valid. + * GDK_WA_COLORMAP: The "colormap" field is valid. + * GDK_WA_VISUAL: The "visual" field is valid. + */ +typedef enum +{ + GDK_WA_TITLE = 1 << 1, + GDK_WA_X = 1 << 2, + GDK_WA_Y = 1 << 3, + GDK_WA_CURSOR = 1 << 4, + GDK_WA_COLORMAP = 1 << 5, + GDK_WA_VISUAL = 1 << 6, + GDK_WA_WMCLASS = 1 << 7 +} GdkWindowAttributesType; + +/* Size restriction enumeration. + */ +typedef enum +{ + GDK_HINT_POS = 1 << 0, + GDK_HINT_MIN_SIZE = 1 << 1, + GDK_HINT_MAX_SIZE = 1 << 2 +} GdkWindowHints; + +/* GC function types. + * Copy: Overwrites destination pixels with the source pixels. + * Invert: Inverts the destination pixels. + * Xor: Xor's the destination pixels with the source pixels. + */ +typedef enum +{ + GDK_COPY, + GDK_INVERT, + GDK_XOR +} GdkFunction; + +/* GC fill types. + * Solid: + * Tiled: + * Stippled: + * OpaqueStippled: + */ +typedef enum +{ + GDK_SOLID, + GDK_TILED, + GDK_STIPPLED, + GDK_OPAQUE_STIPPLED +} GdkFill; + +/* GC line styles + * Solid: + * OnOffDash: + * DoubleDash: + */ +typedef enum +{ + GDK_LINE_SOLID, + GDK_LINE_ON_OFF_DASH, + GDK_LINE_DOUBLE_DASH +} GdkLineStyle; + +/* GC cap styles + * CapNotLast: + * CapButt: + * CapRound: + * CapProjecting: + */ +typedef enum +{ + GDK_CAP_NOT_LAST, + GDK_CAP_BUTT, + GDK_CAP_ROUND, + GDK_CAP_PROJECTING +} GdkCapStyle; + +/* GC join styles + * JoinMiter: + * JoinRound: + * JoinBevel: + */ +typedef enum +{ + GDK_JOIN_MITER, + GDK_JOIN_ROUND, + GDK_JOIN_BEVEL +} GdkJoinStyle; + +/* Cursor types. + */ +typedef enum +{ +#include <gdk/gdkcursors.h> + GDK_LAST_CURSOR +} GdkCursorType; + +/* Event types. + * Nothing: No event occurred. + * Delete: A window delete event was sent by the window manager. + * The specified window should be deleted. + * Destroy: A window has been destroyed. + * Expose: Part of a window has been uncovered. + * MotionNotify: The mouse has moved. + * ButtonPress: A mouse button was pressed. + * ButtonRelease: A mouse button was release. + * KeyPress: A key was pressed. + * KeyRelease: A key was released. + * EnterNotify: A window was entered. + * LeaveNotify: A window was exited. + * FocusChange: The focus window has changed. (The focus window gets + * keyboard events). + * Resize: A window has been resized. + * Map: A window has been mapped. (It is now visible on the screen). + * Unmap: A window has been unmapped. (It is no longer visible on + * the screen). + */ +typedef enum +{ + GDK_NOTHING = -1, + GDK_DELETE = 0, + GDK_DESTROY = 1, + GDK_EXPOSE = 2, + GDK_MOTION_NOTIFY = 3, + GDK_BUTTON_PRESS = 4, + GDK_2BUTTON_PRESS = 5, + GDK_3BUTTON_PRESS = 6, + GDK_BUTTON_RELEASE = 7, + GDK_KEY_PRESS = 8, + GDK_KEY_RELEASE = 9, + GDK_ENTER_NOTIFY = 10, + GDK_LEAVE_NOTIFY = 11, + GDK_FOCUS_CHANGE = 12, + GDK_CONFIGURE = 13, + GDK_MAP = 14, + GDK_UNMAP = 15, + GDK_PROPERTY_NOTIFY = 16, + GDK_SELECTION_CLEAR = 17, + GDK_SELECTION_REQUEST = 18, + GDK_SELECTION_NOTIFY = 19, + GDK_PROXIMITY_IN = 20, + GDK_PROXIMITY_OUT = 21, + GDK_DRAG_BEGIN = 22, + GDK_DRAG_REQUEST = 23, + GDK_DROP_ENTER = 24, + GDK_DROP_LEAVE = 25, + GDK_DROP_DATA_AVAIL = 26, + GDK_CLIENT_EVENT = 27, + GDK_OTHER_EVENT = 9999 +} GdkEventType; + +/* Event masks. (Used to select what types of events a window + * will receive). + */ +typedef enum +{ + GDK_EXPOSURE_MASK = 1 << 1, + GDK_POINTER_MOTION_MASK = 1 << 2, + GDK_POINTER_MOTION_HINT_MASK = 1 << 3, + GDK_BUTTON_MOTION_MASK = 1 << 4, + GDK_BUTTON1_MOTION_MASK = 1 << 5, + GDK_BUTTON2_MOTION_MASK = 1 << 6, + GDK_BUTTON3_MOTION_MASK = 1 << 7, + GDK_BUTTON_PRESS_MASK = 1 << 8, + GDK_BUTTON_RELEASE_MASK = 1 << 9, + GDK_KEY_PRESS_MASK = 1 << 10, + GDK_KEY_RELEASE_MASK = 1 << 11, + GDK_ENTER_NOTIFY_MASK = 1 << 12, + GDK_LEAVE_NOTIFY_MASK = 1 << 13, + GDK_FOCUS_CHANGE_MASK = 1 << 14, + GDK_STRUCTURE_MASK = 1 << 15, + GDK_PROPERTY_CHANGE_MASK = 1 << 16, + GDK_PROXIMITY_IN_MASK = 1 << 17, + GDK_PROXIMITY_OUT_MASK = 1 << 18, + GDK_ALL_EVENTS_MASK = 0x07FFFF +} GdkEventMask; + +/* Types of enter/leave notifications. + * Ancestor: + * Virtual: + * Inferior: + * Nonlinear: + * NonlinearVirtual: + * Unknown: An unknown type of enter/leave event occurred. + */ +typedef enum +{ + GDK_NOTIFY_ANCESTOR = 0, + GDK_NOTIFY_VIRTUAL = 1, + GDK_NOTIFY_INFERIOR = 2, + GDK_NOTIFY_NONLINEAR = 3, + GDK_NOTIFY_NONLINEAR_VIRTUAL = 4, + GDK_NOTIFY_UNKNOWN = 5 +} GdkNotifyType; + +/* Types of modifiers. + */ +typedef enum +{ + GDK_SHIFT_MASK = 1 << 0, + GDK_LOCK_MASK = 1 << 1, + GDK_CONTROL_MASK = 1 << 2, + GDK_MOD1_MASK = 1 << 3, + GDK_MOD2_MASK = 1 << 4, + GDK_MOD3_MASK = 1 << 5, + GDK_MOD4_MASK = 1 << 6, + GDK_MOD5_MASK = 1 << 7, + GDK_BUTTON1_MASK = 1 << 8, + GDK_BUTTON2_MASK = 1 << 9, + GDK_BUTTON3_MASK = 1 << 10, + GDK_BUTTON4_MASK = 1 << 11, + GDK_BUTTON5_MASK = 1 << 12 +} GdkModifierType; + +typedef enum +{ + GDK_CLIP_BY_CHILDREN = 0, + GDK_INCLUDE_INFERIORS = 1 +} GdkSubwindowMode; + +typedef enum +{ + GDK_INPUT_READ = 1 << 0, + GDK_INPUT_WRITE = 1 << 1, + GDK_INPUT_EXCEPTION = 1 << 2 +} GdkInputCondition; + +typedef enum +{ + GDK_OK = 0, + GDK_ERROR = -1, + GDK_ERROR_PARAM = -2, + GDK_ERROR_FILE = -3, + GDK_ERROR_MEM = -4 +} GdkStatus; + +typedef enum +{ + GDK_LSB_FIRST, + GDK_MSB_FIRST +} GdkByteOrder; + +typedef enum +{ + GDK_GC_FOREGROUND = 1 << 0, + GDK_GC_BACKGROUND = 1 << 1, + GDK_GC_FONT = 1 << 2, + GDK_GC_FUNCTION = 1 << 3, + GDK_GC_FILL = 1 << 4, + GDK_GC_TILE = 1 << 5, + GDK_GC_STIPPLE = 1 << 6, + GDK_GC_CLIP_MASK = 1 << 7, + GDK_GC_SUBWINDOW = 1 << 8, + GDK_GC_TS_X_ORIGIN = 1 << 9, + GDK_GC_TS_Y_ORIGIN = 1 << 10, + GDK_GC_CLIP_X_ORIGIN = 1 << 11, + GDK_GC_CLIP_Y_ORIGIN = 1 << 12, + GDK_GC_EXPOSURES = 1 << 13, + GDK_GC_LINE_WIDTH = 1 << 14, + GDK_GC_LINE_STYLE = 1 << 15, + GDK_GC_CAP_STYLE = 1 << 16, + GDK_GC_JOIN_STYLE = 1 << 17 +} GdkGCValuesMask; + +typedef enum +{ + GDK_SELECTION_PRIMARY = 1, + GDK_SELECTION_SECONDARY = 2 +} GdkSelection; + +typedef enum +{ + GDK_PROPERTY_NEW_VALUE, + GDK_PROPERTY_DELETE +} GdkPropertyState; + +typedef enum +{ + GDK_PROP_MODE_REPLACE, + GDK_PROP_MODE_PREPEND, + GDK_PROP_MODE_APPEND +} GdkPropMode; + +/* These definitions are for version 1 of the OffiX D&D protocol, + taken from <OffiX/DragAndDropTypes.h> */ +typedef enum +{ + GDK_DNDTYPE_NOTDND = -1, + GDK_DNDTYPE_UNKNOWN = 0, + GDK_DNDTYPE_RAWDATA = 1, + GDK_DNDTYPE_FILE = 2, + GDK_DNDTYPE_FILES = 3, + GDK_DNDTYPE_TEXT = 4, + GDK_DNDTYPE_DIR = 5, + GDK_DNDTYPE_LINK = 6, + GDK_DNDTYPE_EXE = 7, + GDK_DNDTYPE_URL = 8, + GDK_DNDTYPE_MIME = 9, + GDK_DNDTYPE_END = 10 +} GdkDndType; + +/* Enums for XInput support */ + +typedef enum +{ + GDK_SOURCE_MOUSE, + GDK_SOURCE_PEN, + GDK_SOURCE_ERASER, + GDK_SOURCE_CURSOR +} GdkInputSource; + +typedef enum +{ + GDK_MODE_DISABLED, + GDK_MODE_SCREEN, + GDK_MODE_WINDOW +} GdkInputMode; + +typedef enum +{ + GDK_AXIS_IGNORE, + GDK_AXIS_X, + GDK_AXIS_Y, + GDK_AXIS_PRESSURE, + GDK_AXIS_XTILT, + GDK_AXIS_YTILT, + GDK_AXIS_LAST +} GdkAxisUse; + +/* The next two types define enums for predefined atoms relating + to selections. In general, one will need to use gdk_intern_atom */ + +typedef enum +{ + GDK_TARGET_BITMAP = 5, + GDK_TARGET_COLORMAP = 7, + GDK_TARGET_DRAWABLE = 17, + GDK_TARGET_PIXMAP = 20, + GDK_TARGET_STRING = 31 +} GdkTarget; + +typedef enum +{ + GDK_SELECTION_TYPE_ATOM = 4, + GDK_SELECTION_TYPE_BITMAP = 5, + GDK_SELECTION_TYPE_COLORMAP = 7, + GDK_SELECTION_TYPE_DRAWABLE = 17, + GDK_SELECTION_TYPE_INTEGER = 19, + GDK_SELECTION_TYPE_PIXMAP = 20, + GDK_SELECTION_TYPE_WINDOW = 33, + GDK_SELECTION_TYPE_STRING = 31 +} GdkSelectionType; + +typedef enum +{ + GDK_EXTENSION_EVENTS_NONE, + GDK_EXTENSION_EVENTS_ALL, + GDK_EXTENSION_EVENTS_CURSOR +} GdkExtensionMode; + +typedef void (*GdkInputFunction) (gpointer data, + gint source, + GdkInputCondition condition); + +/* The color type. + * A color consists of red, green and blue values in the + * range 0-65535 and a pixel value. The pixel value is highly + * dependent on the depth and colormap which this color will + * be used to draw into. Therefore, sharing colors between + * colormaps is a bad idea. + */ +struct _GdkColor +{ + gulong pixel; + gushort red; + gushort green; + gushort blue; +}; + +/* The colormap type. + * Colormaps consist of 256 colors. + */ +struct _GdkColormap +{ + GdkColor colors[256]; +}; + +/* The visual type. + * "type" is the type of visual this is (PseudoColor, TrueColor, etc). + * "depth" is the bit depth of this visual. + * "colormap_size" is the size of a colormap for this visual. + * "bits_per_rgb" is the number of significant bits per red, green and blue. + * The red, green and blue masks, shifts and precisions refer + * to value needed to calculate pixel values in TrueColor and DirectColor + * visuals. The "mask" is the significant bits within the pixel. The + * "shift" is the number of bits left we must shift a primary for it + * to be in position (according to the "mask"). "prec" refers to how + * much precision the pixel value contains for a particular primary. + */ +struct _GdkVisual +{ + GdkVisualType type; + gint depth; + GdkByteOrder byte_order; + gint colormap_size; + gint bits_per_rgb; + + guint32 red_mask; + gint red_shift; + gint red_prec; + + guint32 green_mask; + gint green_shift; + gint green_prec; + + guint32 blue_mask; + gint blue_shift; + gint blue_prec; +}; + +struct _GdkWindowAttr +{ + gchar *title; + gint event_mask; + gint16 x, y; + gint16 width; + gint16 height; + GdkWindowClass wclass; + GdkVisual *visual; + GdkColormap *colormap; + GdkWindowType window_type; + GdkCursor *cursor; + gchar *wmclass_name; + gchar *wmclass_class; +}; + +struct _GdkWindow +{ + gpointer user_data; +}; + +struct _GdkImage +{ + GdkImageType type; + GdkVisual *visual; /* visual used to create the image */ + GdkByteOrder byte_order; + guint16 width; + guint16 height; + guint16 depth; + guint16 bpp; /* bytes per pixel */ + guint16 bpl; /* bytes per line */ + gpointer mem; +}; + +struct _GdkGCValues +{ + GdkColor foreground; + GdkColor background; + GdkFont *font; + GdkFunction function; + GdkFill fill; + GdkPixmap *tile; + GdkPixmap *stipple; + GdkPixmap *clip_mask; + GdkSubwindowMode subwindow_mode; + gint ts_x_origin; + gint ts_y_origin; + gint clip_x_origin; + gint clip_y_origin; + gint graphics_exposures; + gint line_width; + GdkLineStyle line_style; + GdkCapStyle cap_style; + GdkJoinStyle join_style; +}; + +struct _GdkGC +{ + gint dummy_var; +}; + +struct _GdkPoint +{ + gint16 x; + gint16 y; +}; + +struct _GdkRectangle +{ + gint16 x; + gint16 y; + guint16 width; + guint16 height; +}; + +struct _GdkSegment +{ + gint16 x1; + gint16 y1; + gint16 x2; + gint16 y2; +}; + +struct _GdkFont +{ + GdkFontType type; + gint ascent; + gint descent; +}; + +struct _GdkCursor +{ + GdkCursorType type; +}; + +/* Types for XInput support */ + +struct _GdkDeviceInfo +{ + guint32 deviceid; + gchar *name; + GdkInputSource source; + GdkInputMode mode; + gint has_cursor; /* TRUE if the X pointer follows device motion */ + gint num_axes; + GdkAxisUse *axes; /* Specifies use for each axis */ +}; + +struct _GdkTimeCoord +{ + guint32 time; + gdouble x; + gdouble y; + gdouble pressure; + gdouble xtilt; + gdouble ytilt; +}; + +struct _GdkEventAny +{ + GdkEventType type; + GdkWindow *window; + gint8 send_event; +}; + +struct _GdkEventExpose +{ + GdkEventType type; + GdkWindow *window; + GdkRectangle area; + gint count; /* If non-zero, how many more events follow. */ +}; + +struct _GdkEventMotion +{ + GdkEventType type; + GdkWindow *window; + guint32 time; + gdouble x; + gdouble y; + gdouble pressure; + gdouble xtilt; + gdouble ytilt; + guint state; + gint16 is_hint; + GdkInputSource source; + guint32 deviceid; +}; + +struct _GdkEventButton +{ + GdkEventType type; + GdkWindow *window; + guint32 time; + gdouble x; + gdouble y; + gdouble pressure; + gdouble xtilt; + gdouble ytilt; + guint state; + guint button; + GdkInputSource source; + guint32 deviceid; +}; + +struct _GdkEventKey +{ + GdkEventType type; + GdkWindow *window; + guint32 time; + guint state; + guint keyval; +}; + +struct _GdkEventCrossing +{ + GdkEventType type; + GdkWindow *window; + GdkWindow *subwindow; + GdkNotifyType detail; +}; + +struct _GdkEventFocus +{ + GdkEventType type; + GdkWindow *window; + gint16 in; +}; + +struct _GdkEventConfigure +{ + GdkEventType type; + GdkWindow *window; + gint16 x, y; + gint16 width; + gint16 height; +}; + +struct _GdkEventProperty +{ + GdkEventType type; + GdkWindow *window; + GdkAtom atom; + guint32 time; + guint state; +}; + +struct _GdkEventSelection +{ + GdkEventType type; + GdkWindow *window; + GdkAtom selection; + GdkAtom target; + GdkAtom property; + guint32 requestor; + guint32 time; +}; + +/* This event type will be used pretty rarely. It only is important + for XInput aware programs that are drawing their own cursor */ + +struct _GdkEventProximity +{ + GdkEventType type; + GdkWindow *window; + guint32 time; + GdkInputSource source; + guint32 deviceid; +}; + +struct _GdkEventDragRequest +{ + GdkEventType type; + GdkWindow *window; + guint32 requestor; + union { + struct { + guint protocol_version:4; + guint sendreply:1; + guint willaccept:1; + guint delete_data:1; /* Do *not* delete if link is sent, only + if data is sent */ + guint senddata:1; + guint reserved:22; + } flags; + glong allflags; + } u; + guint8 isdrop; /* This gdk event can be generated by a couple of + X events - this lets the app know whether the + drop really occurred or we just set the data */ + + GdkPoint drop_coords; + gchar *data_type; +}; + +struct _GdkEventDragBegin +{ + GdkEventType type; + GdkWindow *window; + union { + struct { + guint protocol_version:4; + guint reserved:28; + } flags; + glong allflags; + } u; +}; + +struct _GdkEventDropEnter +{ + GdkEventType type; + GdkWindow *window; + guint32 requestor; + union { + struct { + guint protocol_version:4; + guint sendreply:1; + guint extended_typelist:1; + guint reserved:26; + } flags; + glong allflags; + } u; +}; + +struct _GdkEventDropLeave +{ + GdkEventType type; + GdkWindow *window; + guint32 requestor; + union { + struct { + guint protocol_version:4; + guint reserved:28; + } flags; + glong allflags; + } u; +}; + +struct _GdkEventDropDataAvailable +{ + GdkEventType type; + GdkWindow *window; + guint32 requestor; + union { + struct { + guint protocol_version:4; + guint isdrop:1; + guint reserved:25; + } flags; + glong allflags; + } u; + gchar *data_type; /* MIME type */ + gulong data_numbytes; + gpointer data; +}; + +struct _GdkEventClient +{ + GdkEventType type; + GdkWindow *window; + GdkAtom message_type; + gushort data_format; + union { + char b[20]; + short s[10]; + long l[5]; + } data; +}; + +#ifndef _XLIB_H_ +#define XEvent void +#endif + +struct _GdkEventOther +{ + GdkEventType type; + GdkWindow *window; + XEvent *xevent; +}; + +union _GdkEvent +{ + GdkEventType type; + GdkEventAny any; + GdkEventExpose expose; + GdkEventMotion motion; + GdkEventButton button; + GdkEventKey key; + GdkEventCrossing crossing; + GdkEventFocus focus_change; + GdkEventConfigure configure; + GdkEventProperty property; + GdkEventSelection selection; + GdkEventProximity proximity; + GdkEventDragBegin dragbegin; + GdkEventDragRequest dragrequest; + GdkEventDropEnter dropenter; + GdkEventDropLeave dropleave; + GdkEventDropDataAvailable dropdataavailable; + GdkEventClient client; + GdkEventOther other; +}; + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GDK_TYPES_H__ */ diff --git a/gdk/gdkvisual.c b/gdk/gdkvisual.c new file mode 100644 index 000000000..22acee6f1 --- /dev/null +++ b/gdk/gdkvisual.c @@ -0,0 +1,431 @@ +/* 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 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include <X11/Xlib.h> +#include <X11/Xutil.h> +#include "gdk.h" +#include "gdkprivate.h" + + +static void gdk_visual_add (GdkVisual *visual); +static void gdk_visual_decompose_mask (gulong mask, + gint *shift, + gint *prec); +static guint gdk_visual_hash (Visual *key); +static gint gdk_visual_compare (Visual *a, + Visual *b); + + +static GdkVisualPrivate *system_visual; +static GdkVisualPrivate *visuals; +static gint nvisuals; + +static gint available_depths[4]; +static gint navailable_depths; + +static GdkVisualType available_types[6]; +static gint navailable_types; + +static char* visual_names[] = +{ + "static gray", + "grayscale", + "static color", + "pseudo color", + "true color", + "direct color", +}; + +static GHashTable *visual_hash = NULL; + +void +gdk_visual_init () +{ + static gint possible_depths[5] = { 32, 24, 16, 15, 8 }; + static GdkVisualType possible_types[6] = + { + GDK_VISUAL_DIRECT_COLOR, + GDK_VISUAL_TRUE_COLOR, + GDK_VISUAL_PSEUDO_COLOR, + GDK_VISUAL_STATIC_COLOR, + GDK_VISUAL_GRAYSCALE, + GDK_VISUAL_STATIC_GRAY + }; + + static gint npossible_depths = 5; + static gint npossible_types = 6; + + XVisualInfo *visual_list; + XVisualInfo visual_template; + GdkVisualPrivate temp_visual; + Visual *default_xvisual; + int nxvisuals; + int i, j; + + visual_template.screen = gdk_screen; + visual_list = XGetVisualInfo (gdk_display, VisualScreenMask, &visual_template, &nxvisuals); + visuals = g_new (GdkVisualPrivate, nxvisuals); + + default_xvisual = DefaultVisual (gdk_display, gdk_screen); + + nvisuals = 0; + for (i = 0; i < nxvisuals; i++) + { + if (visual_list[i].depth >= 8) + { +#ifdef __cplusplus + switch (visual_list[i].c_class) +#else /* __cplusplus */ + switch (visual_list[i].class) +#endif /* __cplusplus */ + { + case StaticGray: + visuals[nvisuals].visual.type = GDK_VISUAL_STATIC_GRAY; + break; + case GrayScale: + visuals[nvisuals].visual.type = GDK_VISUAL_GRAYSCALE; + break; + case StaticColor: + visuals[nvisuals].visual.type = GDK_VISUAL_STATIC_COLOR; + break; + case PseudoColor: + visuals[nvisuals].visual.type = GDK_VISUAL_PSEUDO_COLOR; + break; + case TrueColor: + visuals[nvisuals].visual.type = GDK_VISUAL_TRUE_COLOR; + break; + case DirectColor: + visuals[nvisuals].visual.type = GDK_VISUAL_DIRECT_COLOR; + break; + } + + visuals[nvisuals].visual.depth = visual_list[i].depth; + visuals[nvisuals].visual.byte_order = + (ImageByteOrder(gdk_display) == LSBFirst) ? + GDK_LSB_FIRST : GDK_MSB_FIRST; + visuals[nvisuals].visual.red_mask = visual_list[i].red_mask; + visuals[nvisuals].visual.green_mask = visual_list[i].green_mask; + visuals[nvisuals].visual.blue_mask = visual_list[i].blue_mask; + visuals[nvisuals].visual.colormap_size = visual_list[i].colormap_size; + visuals[nvisuals].visual.bits_per_rgb = visual_list[i].bits_per_rgb; + visuals[nvisuals].xvisual = visual_list[i].visual; + + if ((visuals[nvisuals].visual.type == GDK_VISUAL_TRUE_COLOR) || + (visuals[nvisuals].visual.type == GDK_VISUAL_DIRECT_COLOR)) + { + gdk_visual_decompose_mask (visuals[nvisuals].visual.red_mask, + &visuals[nvisuals].visual.red_shift, + &visuals[nvisuals].visual.red_prec); + + gdk_visual_decompose_mask (visuals[nvisuals].visual.green_mask, + &visuals[nvisuals].visual.green_shift, + &visuals[nvisuals].visual.green_prec); + + gdk_visual_decompose_mask (visuals[nvisuals].visual.blue_mask, + &visuals[nvisuals].visual.blue_shift, + &visuals[nvisuals].visual.blue_prec); + } + else + { + visuals[nvisuals].visual.red_mask = 0; + visuals[nvisuals].visual.red_shift = 0; + visuals[nvisuals].visual.red_prec = 0; + + visuals[nvisuals].visual.green_mask = 0; + visuals[nvisuals].visual.green_shift = 0; + visuals[nvisuals].visual.green_prec = 0; + + visuals[nvisuals].visual.blue_mask = 0; + visuals[nvisuals].visual.blue_shift = 0; + visuals[nvisuals].visual.blue_prec = 0; + } + + nvisuals += 1; + } + } + + XFree (visual_list); + + for (i = 0; i < nvisuals; i++) + { + for (j = i+1; j < nvisuals; j++) + { + if (visuals[j].visual.depth >= visuals[i].visual.depth) + { + if ((visuals[j].visual.depth == 8) && (visuals[i].visual.depth == 8)) + { + if (visuals[j].visual.type == GDK_VISUAL_PSEUDO_COLOR) + { + temp_visual = visuals[j]; + visuals[j] = visuals[i]; + visuals[i] = temp_visual; + } + else if ((visuals[i].visual.type != GDK_VISUAL_PSEUDO_COLOR) && + visuals[j].visual.type > visuals[i].visual.type) + { + temp_visual = visuals[j]; + visuals[j] = visuals[i]; + visuals[i] = temp_visual; + } + } + else if ((visuals[j].visual.depth > visuals[i].visual.depth) || + ((visuals[j].visual.depth == visuals[i].visual.depth) && + (visuals[j].visual.type > visuals[i].visual.type))) + { + temp_visual = visuals[j]; + visuals[j] = visuals[i]; + visuals[i] = temp_visual; + } + } + } + } + + for (i = 0; i < nvisuals; i++) + if (default_xvisual->visualid == visuals[i].xvisual->visualid) + { + system_visual = &visuals[i]; + break; + } + + if (gdk_debug_level >= 1) + for (i = 0; i < nvisuals; i++) + g_print ("visual: %s: %d\n", + visual_names[visuals[i].visual.type], + visuals[i].visual.depth); + + navailable_depths = 0; + for (i = 0; i < npossible_depths; i++) + { + for (j = 0; j < nvisuals; j++) + { + if (visuals[j].visual.depth == possible_depths[i]) + { + available_depths[navailable_depths++] = visuals[j].visual.depth; + break; + } + } + } + + if (navailable_depths == 0) + g_error ("unable to find a usable depth"); + + navailable_types = 0; + for (i = 0; i < npossible_types; i++) + { + for (j = 0; j < nvisuals; j++) + { + if (visuals[j].visual.type == possible_types[i]) + { + available_types[navailable_types++] = visuals[j].visual.type; + break; + } + } + } + + for (i = 0; i < nvisuals; i++) + gdk_visual_add ((GdkVisual*) &visuals[i]); + + if (npossible_types == 0) + g_error ("unable to find a usable visual type"); +} + +GdkVisual* +gdk_visual_ref (GdkVisual *visual) +{ + return visual; +} + +void +gdk_visual_unref (GdkVisual *visual) +{ + return; +} + +gint +gdk_visual_get_best_depth () +{ + return available_depths[0]; +} + +GdkVisualType +gdk_visual_get_best_type () +{ + return available_types[0]; +} + +GdkVisual* +gdk_visual_get_system () +{ + return ((GdkVisual*) system_visual); +} + +GdkVisual* +gdk_visual_get_best () +{ + return ((GdkVisual*) &(visuals[0])); +} + +GdkVisual* +gdk_visual_get_best_with_depth (gint depth) +{ + GdkVisual *return_val; + int i; + + return_val = NULL; + for (i = 0; i < nvisuals; i++) + if (depth == visuals[i].visual.depth) + { + return_val = (GdkVisual*) &(visuals[i]); + break; + } + + return return_val; +} + +GdkVisual* +gdk_visual_get_best_with_type (GdkVisualType visual_type) +{ + GdkVisual *return_val; + int i; + + return_val = NULL; + for (i = 0; i < nvisuals; i++) + if (visual_type == visuals[i].visual.type) + { + return_val = (GdkVisual*) &(visuals[i]); + break; + } + + return return_val; +} + +GdkVisual* +gdk_visual_get_best_with_both (gint depth, + GdkVisualType visual_type) +{ + GdkVisual *return_val; + int i; + + return_val = NULL; + for (i = 0; i < nvisuals; i++) + if ((depth == visuals[i].visual.depth) && + (visual_type == visuals[i].visual.type)) + { + return_val = (GdkVisual*) &(visuals[i]); + break; + } + + return return_val; +} + +void +gdk_query_depths (gint **depths, + gint *count) +{ + *count = navailable_depths; + *depths = available_depths; +} + +void +gdk_query_visual_types (GdkVisualType **visual_types, + gint *count) +{ + *count = navailable_types; + *visual_types = available_types; +} + +void +gdk_query_visuals (GdkVisual **visual_return, + gint *count) +{ + *count = nvisuals; + *visual_return = (GdkVisual*) visuals; +} + + +GdkVisual* +gdk_visual_lookup (Visual *xvisual) +{ + GdkVisual *visual; + + if (!visual_hash) + return NULL; + + visual = g_hash_table_lookup (visual_hash, xvisual); + return visual; +} + +GdkVisual* +gdkx_visual_get (VisualID xvisualid) +{ + int i; + + for (i = 0; i < nvisuals; i++) + if (xvisualid == visuals[i].xvisual->visualid) + return (GdkVisual*) &visuals[i]; + + return NULL; +} + + +static void +gdk_visual_add (GdkVisual *visual) +{ + GdkVisualPrivate *private; + + if (!visual_hash) + visual_hash = g_hash_table_new ((GHashFunc) gdk_visual_hash, + (GCompareFunc) gdk_visual_compare); + + private = (GdkVisualPrivate*) visual; + + g_hash_table_insert (visual_hash, private->xvisual, visual); +} + +static void +gdk_visual_decompose_mask (gulong mask, + gint *shift, + gint *prec) +{ + *shift = 0; + *prec = 0; + + while (!(mask & 0x1)) + { + (*shift)++; + mask >>= 1; + } + + while (mask & 0x1) + { + (*prec)++; + mask >>= 1; + } +} + +static guint +gdk_visual_hash (Visual *key) +{ + return key->visualid; +} + +static gint +gdk_visual_compare (Visual *a, + Visual *b) +{ + return (a->visualid == b->visualid); +} diff --git a/gdk/gdkwindow.c b/gdk/gdkwindow.c new file mode 100644 index 000000000..aef1367d9 --- /dev/null +++ b/gdk/gdkwindow.c @@ -0,0 +1,1358 @@ +/* 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 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include <X11/Xlib.h> +#include <X11/Xutil.h> +#include <X11/Xatom.h> +#include <X11/extensions/shape.h> +#include <netinet/in.h> +#include "gdk.h" +#include "gdkinput.h" +#include "gdkprivate.h" +#include <stdlib.h> + +int nevent_masks = 16; +int event_mask_table[18] = +{ + ExposureMask, + PointerMotionMask, + PointerMotionHintMask, + ButtonMotionMask, + Button1MotionMask, + Button2MotionMask, + Button3MotionMask, + ButtonPressMask | OwnerGrabButtonMask, + ButtonReleaseMask | OwnerGrabButtonMask, + KeyPressMask, + KeyReleaseMask, + EnterWindowMask, + LeaveWindowMask, + FocusChangeMask, + StructureNotifyMask, + PropertyChangeMask, + 0, /* PROXIMITY_IN */ + 0 /* PROXIMTY_OUT */ +}; + + +void +gdk_window_init () +{ + XWindowAttributes xattributes; + unsigned int width; + unsigned int height; + unsigned int border_width; + unsigned int depth; + int x, y; + + XGetGeometry (gdk_display, gdk_root_window, &gdk_root_window, + &x, &y, &width, &height, &border_width, &depth); + XGetWindowAttributes (gdk_display, gdk_root_window, &xattributes); + + gdk_root_parent.xdisplay = gdk_display; + gdk_root_parent.xwindow = gdk_root_window; + gdk_root_parent.window_type = GDK_WINDOW_ROOT; + gdk_root_parent.window.user_data = NULL; +} + +GdkWindow* +gdk_window_new (GdkWindow *parent, + GdkWindowAttr *attributes, + gint attributes_mask) +{ + GdkWindow *window; + GdkWindowPrivate *private; + GdkWindowPrivate *parent_private; + GdkVisual *visual; + GdkColormap *colormap; + Display *parent_display; + Window xparent; + Visual *xvisual; + XSetWindowAttributes xattributes; + long xattributes_mask; + XSizeHints size_hints; + XWMHints wm_hints; + XTextProperty text_property; + XClassHint *class_hint; + int x, y, depth; + unsigned int class; + char *title; + int i; + + g_return_val_if_fail (attributes != NULL, NULL); + + if (!parent) + parent = (GdkWindow*) &gdk_root_parent; + + parent_private = (GdkWindowPrivate*) parent; + xparent = parent_private->xwindow; + parent_display = parent_private->xdisplay; + + private = g_new (GdkWindowPrivate, 1); + window = (GdkWindow*) private; + + private->parent = parent; + private->xdisplay = parent_display; + private->destroyed = FALSE; + private->resize_count = 0; + private->ref_count = 1; + xattributes_mask = 0; + + if (attributes_mask & GDK_WA_X) + x = attributes->x; + else + x = 0; + + if (attributes_mask & GDK_WA_Y) + y = attributes->y; + else + y = 0; + + private->x = x; + private->y = y; + private->width = (attributes->width > 1) ? (attributes->width) : (1); + private->height = (attributes->height > 1) ? (attributes->height) : (1); + private->window_type = attributes->window_type; + private->extension_events = FALSE; + private->dnd_drag_data_type = None; + private->dnd_drag_data_typesavail = + private->dnd_drop_data_typesavail = NULL; + private->dnd_drop_enabled = private->dnd_drag_enabled = + private->dnd_drag_accepted = private->dnd_drag_datashow = + private->dnd_drop_data_numtypesavail = + private->dnd_drag_data_numtypesavail = 0; + private->dnd_drag_eventmask = private->dnd_drag_savedeventmask = 0; + + window->user_data = NULL; + + if (attributes_mask & GDK_WA_VISUAL) + visual = attributes->visual; + else + visual = gdk_visual_get_system (); + xvisual = ((GdkVisualPrivate*) visual)->xvisual; + + xattributes.event_mask = StructureNotifyMask; + for (i = 0; i < nevent_masks; i++) + { + if (attributes->event_mask & (1 << (i + 1))) + xattributes.event_mask |= event_mask_table[i]; + } + + if (xattributes.event_mask) + xattributes_mask |= CWEventMask; + + if (attributes->wclass == GDK_INPUT_OUTPUT) + { + class = InputOutput; + depth = visual->depth; + + if (attributes_mask & GDK_WA_COLORMAP) + colormap = attributes->colormap; + else + colormap = gdk_colormap_get_system (); + + xattributes.background_pixel = BlackPixel (gdk_display, gdk_screen); + xattributes.border_pixel = BlackPixel (gdk_display, gdk_screen); + xattributes_mask |= CWBorderPixel | CWBackPixel; + + switch (private->window_type) + { + case GDK_WINDOW_TOPLEVEL: + xattributes.colormap = ((GdkColormapPrivate*) colormap)->xcolormap; + xattributes_mask |= CWColormap; + + xparent = gdk_root_window; + break; + + case GDK_WINDOW_CHILD: + xattributes.colormap = ((GdkColormapPrivate*) colormap)->xcolormap; + xattributes_mask |= CWColormap; + break; + + case GDK_WINDOW_DIALOG: + xattributes.colormap = ((GdkColormapPrivate*) colormap)->xcolormap; + xattributes_mask |= CWColormap; + + xparent = gdk_root_window; + break; + + case GDK_WINDOW_TEMP: + xattributes.colormap = ((GdkColormapPrivate*) colormap)->xcolormap; + xattributes_mask |= CWColormap; + + xparent = gdk_root_window; + + xattributes.save_under = True; + xattributes.override_redirect = True; + xattributes.cursor = None; + xattributes_mask |= CWSaveUnder | CWOverrideRedirect; + break; + case GDK_WINDOW_ROOT: + g_error ("cannot make windows of type GDK_WINDOW_ROOT"); + break; + case GDK_WINDOW_PIXMAP: + g_error ("cannot make windows of type GDK_WINDOW_PIXMAP (use gdk_pixmap_new)"); + break; + } + } + else + { + depth = 1; + class = InputOnly; + colormap = NULL; + } + + private->xwindow = XCreateWindow (private->xdisplay, xparent, + x, y, private->width, private->height, + 0, depth, class, xvisual, + xattributes_mask, &xattributes); + gdk_xid_table_insert (&private->xwindow, window); + + switch (private->window_type) + { + case GDK_WINDOW_DIALOG: + XSetTransientForHint (private->xdisplay, private->xwindow, xparent); + case GDK_WINDOW_TOPLEVEL: + case GDK_WINDOW_TEMP: + XSetWMProtocols (private->xdisplay, private->xwindow, gdk_wm_window_protocols, 2); + break; + case GDK_WINDOW_CHILD: + if ((attributes->wclass == GDK_INPUT_OUTPUT) && + (colormap != gdk_colormap_get_system ()) && + (colormap != gdk_window_get_colormap (gdk_window_get_toplevel (window)))) + { + g_print ("adding colormap window\n"); + gdk_window_add_colormap_windows (window); + } + break; + default: + break; + } + + size_hints.flags = PSize | PBaseSize; + size_hints.width = private->width; + size_hints.height = private->height; + size_hints.base_width = private->width; + size_hints.base_height = private->height; + + wm_hints.flags = InputHint | StateHint | WindowGroupHint; + wm_hints.window_group = gdk_leader_window; + wm_hints.input = True; + wm_hints.initial_state = NormalState; + + XSetWMNormalHints (private->xdisplay, private->xwindow, &size_hints); + XSetWMHints (private->xdisplay, private->xwindow, &wm_hints); + + if (attributes_mask & GDK_WA_TITLE) + title = attributes->title; + else + title = gdk_progname; + + if (XStringListToTextProperty (&title, 1, &text_property)) + { + XSetWMName (private->xdisplay, private->xwindow, &text_property); + XSetWMIconName (private->xdisplay, private->xwindow, &text_property); + XFree (text_property.value); + } + + if (attributes_mask & GDK_WA_WMCLASS) + { + class_hint = XAllocClassHint (); + class_hint->res_name = attributes->wmclass_name; + class_hint->res_class = attributes->wmclass_class; + XSetClassHint (private->xdisplay, private->xwindow, class_hint); + XFree (class_hint); + } + + gdk_window_set_cursor (window, ((attributes_mask & GDK_WA_CURSOR) ? + (attributes->cursor) : + NULL)); + + return window; +} + +GdkWindow * +gdk_window_foreign_new (guint32 anid) +{ + GdkWindow *window; + GdkWindowPrivate *private; + XWindowAttributes attrs; + + private = g_new (GdkWindowPrivate, 1); + window = (GdkWindow*) private; + + XGetWindowAttributes (gdk_display, anid, &attrs); + + private->parent = NULL; + private->xwindow = anid; + private->xdisplay = gdk_display; + private->x = attrs.x; + private->y = attrs.y; + private->width = attrs.width; + private->height = attrs.height; + private->resize_count = 0; + private->ref_count = 1; + if (anid == attrs.root) + private->window_type = GDK_WINDOW_ROOT; + else + private->window_type = GDK_WINDOW_TOPLEVEL; + /* the above is probably wrong, but it may not be worth the extra + X call to get it right */ + + private->destroyed = FALSE; + private->extension_events = 0; + + window->user_data = NULL; + + gdk_xid_table_insert (&private->xwindow, window); + + return window; +} + +void +gdk_window_destroy (GdkWindow *window) +{ + GdkWindowPrivate *private; + GdkWindowPrivate *temp_private; + GdkWindow *temp_window; + GList *children; + GList *tmp; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + if(private->dnd_drag_data_numtypesavail > 0) + { + free(private->dnd_drag_data_typesavail); + private->dnd_drag_data_typesavail = NULL; + } + if(private->dnd_drop_data_numtypesavail > 0) + { + free(private->dnd_drop_data_typesavail); + private->dnd_drop_data_typesavail = NULL; + } + + switch (private->window_type) + { + case GDK_WINDOW_TOPLEVEL: + case GDK_WINDOW_CHILD: + case GDK_WINDOW_DIALOG: + case GDK_WINDOW_TEMP: + if (private->ref_count >= 1) + private->ref_count -= 1; + + if (!private->destroyed || (private->destroyed == 2)) + { + children = gdk_window_get_children (window); + tmp = children; + + while (tmp) + { + temp_window = tmp->data; + tmp = tmp->next; + + temp_private = (GdkWindowPrivate*) temp_window; + if (temp_private && !temp_private->destroyed) + /* Removes some nice coredumps... /David */ + { + temp_private->destroyed = 2; + temp_private->ref_count += 1; + gdk_window_destroy (temp_window); + } + } + + g_list_free (children); + + if (!private->destroyed) + XDestroyWindow (private->xdisplay, private->xwindow); + private->destroyed = TRUE; + } + break; + + case GDK_WINDOW_ROOT: + g_error ("attempted to destroy root window"); + break; + + case GDK_WINDOW_PIXMAP: + g_warning ("called gdk_window_destroy on a pixmap (use gdk_pixmap_destroy)"); + gdk_pixmap_destroy (window); + break; + } +} + +void +gdk_window_real_destroy (GdkWindow *window) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + + if (private->extension_events != 0) + gdk_input_window_destroy (window); + + if (private->ref_count == 0) + { + gdk_xid_table_remove (private->xwindow); + g_free (window); + } +} + +GdkWindow* +gdk_window_ref (GdkWindow *window) +{ + GdkWindowPrivate *private = (GdkWindowPrivate *)window; + g_return_if_fail (window != NULL); + + private->ref_count += 1; + return window; +} + +void +gdk_window_unref (GdkWindow *window) +{ + GdkWindowPrivate *private = (GdkWindowPrivate *)window; + g_return_if_fail (window != NULL); + + private->ref_count -= 1; + if (private->ref_count == 0) + gdk_window_real_destroy (window); +} + +void +gdk_window_show (GdkWindow *window) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + if (!private->destroyed) + { + XRaiseWindow (private->xdisplay, private->xwindow); + XMapWindow (private->xdisplay, private->xwindow); + } +} + +void +gdk_window_hide (GdkWindow *window) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + if (!private->destroyed) + XUnmapWindow (private->xdisplay, private->xwindow); +} + +void +gdk_window_move (GdkWindow *window, + gint x, + gint y) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + XMoveWindow (private->xdisplay, private->xwindow, x, y); + + if (private->window_type == GDK_WINDOW_CHILD) + { + private->x = x; + private->y = y; + } +} + +void +gdk_window_resize (GdkWindow *window, + gint width, + gint height) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + if (width < 1) + width = 1; + if (height < 1) + height = 1; + + private = (GdkWindowPrivate*) window; + + if (!private->destroyed && + ((private->resize_count > 0) || + (private->width != (guint16) width) || + (private->height != (guint16) height))) + { + XResizeWindow (private->xdisplay, private->xwindow, width, height); + private->resize_count += 1; + + if (private->window_type == GDK_WINDOW_CHILD) + { + private->width = width; + private->height = height; + } + } +} + +void +gdk_window_move_resize (GdkWindow *window, + gint x, + gint y, + gint width, + gint height) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + if (width < 1) + width = 1; + if (height < 1) + height = 1; + + private = (GdkWindowPrivate*) window; + XMoveResizeWindow (private->xdisplay, private->xwindow, x, y, width, height); + + if (!private->destroyed && + (private->window_type == GDK_WINDOW_CHILD)) + { + private->x = x; + private->y = y; + private->width = width; + private->height = height; + } +} + +void +gdk_window_reparent (GdkWindow *window, + GdkWindow *new_parent, + gint x, + gint y) +{ + GdkWindowPrivate *window_private; + GdkWindowPrivate *parent_private; + + g_return_if_fail (window != NULL); + + if (!new_parent) + new_parent = (GdkWindow*) &gdk_root_parent; + + window_private = (GdkWindowPrivate*) window; + parent_private = (GdkWindowPrivate*) new_parent; + + XReparentWindow (window_private->xdisplay, + window_private->xwindow, + parent_private->xwindow, + x, y); +} + +void +gdk_window_clear (GdkWindow *window) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + + XClearWindow (private->xdisplay, private->xwindow); +} + +void +gdk_window_clear_area (GdkWindow *window, + gint x, + gint y, + gint width, + gint height) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + + if (!private->destroyed) + XClearArea (private->xdisplay, private->xwindow, + x, y, width, height, False); +} + +void +gdk_window_clear_area_e (GdkWindow *window, + gint x, + gint y, + gint width, + gint height) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + + if (!private->destroyed) + XClearArea (private->xdisplay, private->xwindow, + x, y, width, height, True); +} + +void +gdk_window_copy_area (GdkWindow *window, + GdkGC *gc, + gint x, + gint y, + GdkWindow *source_window, + gint source_x, + gint source_y, + gint width, + gint height) +{ + GdkWindowPrivate *src_private; + GdkWindowPrivate *dest_private; + GdkGCPrivate *gc_private; + + g_return_if_fail (window != NULL); + g_return_if_fail (gc != NULL); + + if (source_window == NULL) + source_window = window; + + src_private = (GdkWindowPrivate*) source_window; + dest_private = (GdkWindowPrivate*) window; + gc_private = (GdkGCPrivate*) gc; + + if (!src_private->destroyed && !dest_private->destroyed) + { + XCopyArea (dest_private->xdisplay, src_private->xwindow, dest_private->xwindow, + gc_private->xgc, + source_x, source_y, + width, height, + x, y); + } +} + +void +gdk_window_raise (GdkWindow *window) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + + if (!private->destroyed) + XRaiseWindow (private->xdisplay, private->xwindow); +} + +void +gdk_window_lower (GdkWindow *window) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + + if (!private->destroyed) + XLowerWindow (private->xdisplay, private->xwindow); +} + +void +gdk_window_set_user_data (GdkWindow *window, + gpointer user_data) +{ + g_return_if_fail (window != NULL); + + window->user_data = user_data; +} + +void +gdk_window_set_hints (GdkWindow *window, + gint x, + gint y, + gint min_width, + gint min_height, + gint max_width, + gint max_height, + gint flags) +{ + GdkWindowPrivate *private; + XSizeHints size_hints; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + size_hints.flags = 0; + + if (flags & GDK_HINT_POS) + { + size_hints.flags |= PPosition; + size_hints.x = x; + size_hints.y = y; + } + + if (flags & GDK_HINT_MIN_SIZE) + { + size_hints.flags |= PMinSize; + size_hints.min_width = min_width; + size_hints.min_height = min_height; + } + + if (flags & GDK_HINT_MAX_SIZE) + { + size_hints.flags |= PMaxSize; + size_hints.max_width = max_width; + size_hints.max_height = max_height; + } + + if (flags) + XSetWMNormalHints (private->xdisplay, private->xwindow, &size_hints); +} + +void +gdk_window_set_title (GdkWindow *window, + const gchar *title) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + XStoreName (private->xdisplay, private->xwindow, title); + XSetIconName (private->xdisplay, private->xwindow, title); +} + +void +gdk_window_set_background (GdkWindow *window, + GdkColor *color) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + XSetWindowBackground (private->xdisplay, private->xwindow, color->pixel); +} + +void +gdk_window_set_back_pixmap (GdkWindow *window, + GdkPixmap *pixmap, + gint parent_relative) +{ + GdkWindowPrivate *window_private; + GdkPixmapPrivate *pixmap_private; + Pixmap xpixmap; + + g_return_if_fail (window != NULL); + + window_private = (GdkWindowPrivate*) window; + pixmap_private = (GdkPixmapPrivate*) pixmap; + + if (pixmap) + xpixmap = pixmap_private->xwindow; + else + xpixmap = None; + + if (parent_relative) + xpixmap = ParentRelative; + + XSetWindowBackgroundPixmap (window_private->xdisplay, window_private->xwindow, xpixmap); +} + +void +gdk_window_set_cursor (GdkWindow *window, + GdkCursor *cursor) +{ + GdkWindowPrivate *window_private; + GdkCursorPrivate *cursor_private; + Cursor xcursor; + + g_return_if_fail (window != NULL); + + window_private = (GdkWindowPrivate*) window; + cursor_private = (GdkCursorPrivate*) cursor; + + if (!cursor) + xcursor = None; + else + xcursor = cursor_private->xcursor; + + XDefineCursor (window_private->xdisplay, window_private->xwindow, xcursor); +} + +void +gdk_window_set_colormap (GdkWindow *window, + GdkColormap *colormap) +{ + GdkWindowPrivate *window_private; + GdkColormapPrivate *colormap_private; + + g_return_if_fail (window != NULL); + g_return_if_fail (colormap != NULL); + + window_private = (GdkWindowPrivate*) window; + colormap_private = (GdkColormapPrivate*) colormap; + + XSetWindowColormap (window_private->xdisplay, + window_private->xwindow, + colormap_private->xcolormap); + + if (window_private->window_type != GDK_WINDOW_TOPLEVEL) + gdk_window_add_colormap_windows (window); +} + +void +gdk_window_get_user_data (GdkWindow *window, + gpointer *data) +{ + g_return_if_fail (window != NULL); + + *data = window->user_data; +} + +void +gdk_window_get_geometry (GdkWindow *window, + gint *x, + gint *y, + gint *width, + gint *height, + gint *depth) +{ + GdkWindowPrivate *window_private; + Window root; + gint tx; + gint ty; + guint twidth; + guint theight; + guint tborder_width; + guint tdepth; + + if (!window) + window = (GdkWindow*) &gdk_root_parent; + + window_private = (GdkWindowPrivate*) window; + + XGetGeometry (window_private->xdisplay, window_private->xwindow, + &root, &tx, &ty, &twidth, &theight, &tborder_width, &tdepth); + + if (x) + *x = tx; + if (y) + *y = ty; + if (width) + *width = twidth; + if (height) + *height = theight; + if (depth) + *depth = tdepth; +} + +void +gdk_window_get_position (GdkWindow *window, + gint *x, + gint *y) +{ + GdkWindowPrivate *window_private; + + g_return_if_fail (window != NULL); + + window_private = (GdkWindowPrivate*) window; + + if (x) + *x = window_private->x; + if (y) + *y = window_private->y; +} + +void +gdk_window_get_size (GdkWindow *window, + gint *width, + gint *height) +{ + GdkWindowPrivate *window_private; + + g_return_if_fail (window != NULL); + + window_private = (GdkWindowPrivate*) window; + + if (width) + *width = window_private->width; + if (height) + *height = window_private->height; +} + + +GdkVisual* +gdk_window_get_visual (GdkWindow *window) +{ + GdkWindowPrivate *window_private; + XWindowAttributes window_attributes; + + g_return_val_if_fail (window != NULL, NULL); + + window_private = (GdkWindowPrivate*) window; + while (window_private && (window_private->window_type == GDK_WINDOW_PIXMAP)) + window_private = (GdkWindowPrivate*) window_private->parent; + + if (window_private) + { + XGetWindowAttributes (window_private->xdisplay, + window_private->xwindow, + &window_attributes); + + return gdk_visual_lookup (window_attributes.visual); + } + + return NULL; +} + +GdkColormap* +gdk_window_get_colormap (GdkWindow *window) +{ + GdkWindowPrivate *window_private; + XWindowAttributes window_attributes; + + g_return_val_if_fail (window != NULL, NULL); + + window_private = (GdkWindowPrivate*) window; + + XGetWindowAttributes (window_private->xdisplay, + window_private->xwindow, + &window_attributes); + + return gdk_colormap_lookup (window_attributes.colormap); +} + +GdkWindowType +gdk_window_get_type (GdkWindow *window) +{ + GdkWindowPrivate *window_private; + + g_return_val_if_fail (window != NULL, (GdkWindowType) -1); + + window_private = (GdkWindowPrivate*) window; + return window_private->window_type; +} + +gint +gdk_window_get_origin (GdkWindow *window, + gint *x, + gint *y) +{ + GdkWindowPrivate *private; + gint return_val; + Window child; + gint tx, ty; + + g_return_val_if_fail (window != NULL, 0); + + private = (GdkWindowPrivate*) window; + + return_val = XTranslateCoordinates (private->xdisplay, + private->xwindow, + gdk_root_window, + 0, 0, &tx, &ty, + &child); + + if (x) + *x = tx; + if (y) + *y = ty; + + return return_val; +} + +GdkWindow* +gdk_window_get_pointer (GdkWindow *window, + gint *x, + gint *y, + GdkModifierType *mask) +{ + GdkWindowPrivate *private; + GdkWindow *return_val; + Window root; + Window child; + int rootx, rooty; + int winx, winy; + unsigned int xmask; + + if (!window) + window = (GdkWindow*) &gdk_root_parent; + + private = (GdkWindowPrivate*) window; + + return_val = NULL; + if (XQueryPointer (private->xdisplay, private->xwindow, &root, &child, + &rootx, &rooty, &winx, &winy, &xmask)) + { + if (x) *x = winx; + if (y) *y = winy; + if (mask) *mask = xmask; + + if (child) + return_val = gdk_window_lookup (child); + } + + return return_val; +} + +GdkWindow* +gdk_window_get_parent (GdkWindow *window) +{ + g_return_val_if_fail (window != NULL, NULL); + + return ((GdkWindowPrivate*) window)->parent; +} + +GdkWindow* +gdk_window_get_toplevel (GdkWindow *window) +{ + GdkWindowPrivate *private; + + g_return_val_if_fail (window != NULL, NULL); + + private = (GdkWindowPrivate*) window; + + while (private->window_type == GDK_WINDOW_CHILD) + { + window = ((GdkWindowPrivate*) window)->parent; + private = (GdkWindowPrivate*) window; + } + + return window; +} + +GList* +gdk_window_get_children (GdkWindow *window) +{ + GdkWindowPrivate *private; + GdkWindow *child; + GList *children; + Window root; + Window parent; + Window *xchildren; + unsigned int nchildren; + unsigned int i; + + g_return_val_if_fail (window != NULL, NULL); + + private = (GdkWindowPrivate*) window; + + XQueryTree (private->xdisplay, private->xwindow, + &root, &parent, &xchildren, &nchildren); + + children = NULL; + + if (nchildren > 0) + { + for (i = 0; i < nchildren; i++) + { + child = gdk_window_lookup (xchildren[i]); + if (child) + children = g_list_prepend (children, child); + } + + XFree (xchildren); + } + + return children; +} + +GdkEventMask +gdk_window_get_events (GdkWindow *window) +{ + XWindowAttributes attrs; + GdkEventMask event_mask; + int i; + + XGetWindowAttributes (gdk_display, ((GdkWindowPrivate *)window)->xwindow, + &attrs); + + event_mask = 0; + for (i = 0; i < nevent_masks; i++) + { + if (attrs.your_event_mask & event_mask_table[i]) + event_mask |= 1 << (i + 1); + } + + return event_mask; +} + +void +gdk_window_set_events (GdkWindow *window, + GdkEventMask event_mask) +{ + long xevent_mask; + int i; + + xevent_mask = StructureNotifyMask; + for (i = 0; i < nevent_masks; i++) + { + if (event_mask & (1 << (i + 1))) + xevent_mask |= event_mask_table[i]; + } + + XSelectInput (gdk_display, ((GdkWindowPrivate *)window)->xwindow, + xevent_mask); +} + +void +gdk_window_add_colormap_windows (GdkWindow *window) +{ + GdkWindow *toplevel; + GdkWindowPrivate *toplevel_private; + GdkWindowPrivate *window_private; + Window *old_windows; + Window *new_windows; + int i, count; + + g_return_if_fail (window != NULL); + + toplevel = gdk_window_get_toplevel (window); + toplevel_private = (GdkWindowPrivate*) toplevel; + window_private = (GdkWindowPrivate*) window; + + if (!XGetWMColormapWindows (toplevel_private->xdisplay, + toplevel_private->xwindow, + &old_windows, &count)) + { + old_windows = NULL; + count = 0; + } + + for (i = 0; i < count; i++) + if (old_windows[i] == window_private->xwindow) + return; + + new_windows = g_new (Window, count + 1); + + for (i = 0; i < count; i++) + new_windows[i] = old_windows[i]; + new_windows[count] = window_private->xwindow; + + XSetWMColormapWindows (toplevel_private->xdisplay, + toplevel_private->xwindow, + new_windows, count + 1); + + g_free (new_windows); + if (old_windows) + XFree (old_windows); +} + +/* + * This needs the X11 shape extension. + * If not available, simply remove the call to + * XShapeCombineMask. Shaped windows will look + * ugly, but programs still work. Stefan Wille + */ +void +gdk_window_shape_combine_mask (GdkWindow *window, + GdkBitmap *mask, + gint x, gint y) +{ + GdkWindowPrivate *window_private; + GdkWindowPrivate *pixmap_private; + + g_return_if_fail (window != NULL); + g_return_if_fail (mask != NULL); + + window_private = (GdkWindowPrivate*) window; + pixmap_private = (GdkWindowPrivate*) mask; + + XShapeCombineMask (window_private->xdisplay, + window_private->xwindow, + ShapeBounding, + x, y, /* offset */ + (Pixmap)pixmap_private->xwindow, + ShapeSet); +} + +void +gdk_dnd_drag_addwindow (GdkWindow *window) +{ + GdkWindowPrivate *window_private; + + g_return_if_fail (window != NULL); + + window_private = (GdkWindowPrivate *) window; + + if (window_private->dnd_drag_enabled == 1 && gdk_dnd.drag_really == 0) + { + gdk_dnd.drag_numwindows++; + gdk_dnd.drag_startwindows = g_realloc (gdk_dnd.drag_startwindows, + gdk_dnd.drag_numwindows + * sizeof(GdkWindow *)); + gdk_dnd.drag_startwindows[gdk_dnd.drag_numwindows - 1] = window; + window_private->dnd_drag_accepted = 0; + } + else + g_warning ("dnd_really is 1 or drag is not enabled! can't addwindow\n"); +} + +void +gdk_window_dnd_drag_set (GdkWindow *window, + guint8 drag_enable, + gchar **typelist, + guint numtypes) +{ + GdkWindowPrivate *window_private; + int i, wasset = 0; + + g_return_if_fail (window != NULL); + window_private = (GdkWindowPrivate *) window; + + window_private->dnd_drag_enabled = drag_enable ? 1 : 0; + + if (drag_enable) + { + g_return_if_fail(typelist != NULL); + + if (window_private->dnd_drag_data_numtypesavail > 3) + wasset = 1; + window_private->dnd_drag_data_numtypesavail = numtypes; + + window_private->dnd_drag_data_typesavail = + g_realloc (window_private->dnd_drag_data_typesavail, + (numtypes + 1) * sizeof (GdkAtom)); + + for (i = 0; i < numtypes; i++) + { + /* Allow blanket use of ALL to get anything... */ + if (strcmp (typelist[i], "ALL")) + window_private->dnd_drag_data_typesavail[i] = + gdk_atom_intern (typelist[i], FALSE); + else + window_private->dnd_drag_data_typesavail[i] = None; + } + + /* + * set our extended type list if we need to + */ + if (numtypes > 3) + gdk_property_change(window, gdk_dnd.gdk_XdeTypelist, + XA_PRIMARY, 32, GDK_PROP_MODE_REPLACE, + (guchar *)(window_private->dnd_drag_data_typesavail + + (sizeof(GdkAtom) * 3)), + (numtypes - 3) * sizeof(GdkAtom)); + else if (wasset) + gdk_property_delete (window, gdk_dnd.gdk_XdeTypelist); + } + else + { + free (window_private->dnd_drag_data_typesavail); + window_private->dnd_drag_data_typesavail = NULL; + window_private->dnd_drag_data_numtypesavail = 0; + } +} + +void +gdk_window_dnd_drop_set (GdkWindow *window, + guint8 drop_enable, + gchar **typelist, + guint numtypes, + guint8 destructive_op) +{ + GdkWindowPrivate *window_private; + int i; + + g_return_if_fail (window != NULL); + + window_private = (GdkWindowPrivate *) window; + + window_private->dnd_drop_enabled = drop_enable ? 1 : 0; + if (drop_enable) + { + g_return_if_fail(typelist != NULL); + + window_private->dnd_drop_data_numtypesavail = numtypes; + + window_private->dnd_drop_data_typesavail = + g_realloc (window_private->dnd_drop_data_typesavail, + (numtypes + 1) * sizeof (GdkAtom)); + + for (i = 0; i < numtypes; i++) + window_private->dnd_drop_data_typesavail[i] = + gdk_atom_intern (typelist[i], FALSE); + + window_private->dnd_drop_destructive_op = destructive_op; + } +} + +/* + * This is used to reply to a GDK_DRAG_REQUEST event + * (which may be generated by XdeRequest or a confirmed drop... + */ +void +gdk_window_dnd_data_set (GdkWindow *window, + GdkEvent *event, + gpointer data, + gulong data_numbytes) +{ + GdkWindowPrivate *window_private; + XEvent sev; + GdkEventDropDataAvailable tmp_ev; + gchar *tmp; + + g_return_if_fail (window != NULL); + g_return_if_fail (event != NULL); + g_return_if_fail (data != NULL); + g_return_if_fail (data_numbytes > 0); + g_return_if_fail (event->type == GDK_DRAG_REQUEST); + + g_free (event->dragrequest.data_type); + event->dragrequest.data_type = NULL; + + window_private = (GdkWindowPrivate *) window; + g_return_if_fail (window_private->dnd_drag_accepted != 0); + + /* We set the property on our window... */ + gdk_property_change (window, window_private->dnd_drag_data_type, + XA_PRIMARY, 8, GDK_PROP_MODE_REPLACE, data, + data_numbytes); + tmp = gdk_atom_name(window_private->dnd_drag_data_type); + g_print("DnD type %s on window %ld\n", tmp, window_private->xwindow); + g_free(tmp); + + /* + * Then we send the event to tell the receiving window that the + * drop has happened + */ + tmp_ev.u.allflags = 0; + tmp_ev.u.flags.protocol_version = DND_PROTOCOL_VERSION; + tmp_ev.u.flags.isdrop = event->dragrequest.isdrop; + + sev.xclient.type = ClientMessage; + sev.xclient.format = 32; + sev.xclient.window = event->dragrequest.requestor; + sev.xclient.message_type = gdk_dnd.gdk_XdeDataAvailable; + sev.xclient.data.l[0] = window_private->xwindow; + sev.xclient.data.l[1] = tmp_ev.u.allflags; + sev.xclient.data.l[2] = window_private->dnd_drag_data_type; + + if (event->dragrequest.isdrop) + sev.xclient.data.l[3] = event->dragrequest.drop_coords.x + + (event->dragrequest.drop_coords.y << 16); + else + sev.xclient.data.l[3] = 0; + + sev.xclient.data.l[4] = 0; + + XSendEvent (gdk_display, event->dragrequest.requestor, False, + NoEventMask, &sev); +} diff --git a/gdk/gdkx.h b/gdk/gdkx.h new file mode 100644 index 000000000..cb8e33b44 --- /dev/null +++ b/gdk/gdkx.h @@ -0,0 +1,48 @@ +/* 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 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef __GDK_X_H__ +#define __GDK_X_H__ + +#include <gdk/gdkprivate.h> + + +#define GDK_ROOT_WINDOW() gdk_root_window +#define GDK_ROOT_PARENT() &gdk_root_parent +#define GDK_DISPLAY() gdk_display +#define GDK_WINDOW_XDISPLAY(win) (((GdkWindowPrivate*) win)->xdisplay) +#define GDK_WINDOW_XWINDOW(win) (((GdkWindowPrivate*) win)->xwindow) +#define GDK_IMAGE_XDISPLAY(image) (((GdkImagePrivate*) image)->xdisplay) +#define GDK_IMAGE_XIMAGE(image) (((GdkImagePrivate*) image)->ximage) +#define GDK_GC_XDISPLAY(gc) (((GdkGCPrivate*) gc)->xdisplay) +#define GDK_GC_XGC(gc) (((GdkGCPrivate*) gc)->xgc) +#define GDK_COLORMAP_XDISPLAY(cmap) (((GdkColormapPrivate*) cmap)->xdisplay) +#define GDK_COLORMAP_XCOLORMAP(cmap) (((GdkColormapPrivate*) cmap)->xcolormap) +#define GDK_VISUAL_XVISUAL(vis) (((GdkVisualPrivate*) vis)->xvisual) +#define GDK_FONT_XDISPLAY(font) (((GdkFontPrivate*) font)->xdisplay) +#define GDK_FONT_XFONT(font) (((GdkFontPrivate*) font)->xfont) + + +GdkVisual* gdkx_visual_get (VisualID xvisualid); +GdkColormap* gdkx_colormap_get (Colormap xcolormap); +/* Utility function in gdk.c - not sure where it belongs, but it's + needed in more than one place, so make it public */ +Window gdk_get_client_window (Display *dpy, + Window win); + + +#endif /* __GDK_X_H__ */ diff --git a/gdk/gdkxid.c b/gdk/gdkxid.c new file mode 100644 index 000000000..7ee6075c5 --- /dev/null +++ b/gdk/gdkxid.c @@ -0,0 +1,74 @@ +/* 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 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include "gdkprivate.h" + + +static guint gdk_xid_hash (XID *xid); +static gint gdk_xid_compare (XID *a, + XID *b); + + +GHashTable *xid_ht = NULL; + + +void +gdk_xid_table_insert (XID *xid, + gpointer data) +{ + g_return_if_fail (xid != NULL); + + if (!xid_ht) + xid_ht = g_hash_table_new ((GHashFunc) gdk_xid_hash, + (GCompareFunc) gdk_xid_compare); + + g_hash_table_insert (xid_ht, xid, data); +} + +void +gdk_xid_table_remove (XID xid) +{ + if (!xid_ht) + xid_ht = g_hash_table_new ((GHashFunc) gdk_xid_hash, + (GCompareFunc) gdk_xid_compare); + + g_hash_table_remove (xid_ht, &xid); +} + +gpointer +gdk_xid_table_lookup (XID xid) +{ + gpointer data; + + data = g_hash_table_lookup (xid_ht, &xid); + + return data; +} + + +static guint +gdk_xid_hash (XID *xid) +{ + return *xid; +} + +static gint +gdk_xid_compare (XID *a, + XID *b) +{ + return (*a == *b); +} diff --git a/gdk/gxid.c b/gdk/gxid.c new file mode 100644 index 000000000..219c08bfe --- /dev/null +++ b/gdk/gxid.c @@ -0,0 +1,844 @@ +/* + * gxid version 0.3 + * + * Copyright 1997 Owen Taylor <owt1@cornell.edu> +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <signal.h> +#include <sys/time.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <X11/Xlib.h> +#include <X11/extensions/XInput.h> + +#include "gxid_proto.h" + +/* #define DEBUG_CLIENTS */ +/* #define DEBUG_EVENTS */ + +char *program_name; +Display *dpy; +Window root_window; /* default root window of dpy */ +int port = 0; /* port to listen on */ +int socket_fd = 0; /* file descriptor of socket */ +typedef struct GxidWindow_ GxidWindow; + +typedef struct GxidDevice_ GxidDevice; +struct GxidDevice_ { + XID id; + int exclusive; + int ispointer; + + XDevice *xdevice; + int motionnotify_type; + int changenotify_type; +}; + +struct GxidWindow_ { + Window xwindow; + /* Immediate child of root that is ancestor of window */ + Window root_child; + int num_devices; + GxidDevice **devices; +}; + +GxidDevice **devices = NULL; +int num_devices = 0; +GxidWindow **windows = NULL; +int num_windows = 0; + +void +handler(int signal) +{ + fprintf(stderr,"%s: dying on signal %d\n",program_name,signal); + if (socket_fd) + close(socket_fd); + exit(1); +} + +void +init_socket() +{ + struct sockaddr_in sin; + + socket_fd = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP); + if (socket_fd < 0) + { + fprintf (stderr, "%s: error getting socket\n", + program_name); + exit(1); + } + + sin.sin_family = AF_INET; + sin.sin_port = htons(port); + sin.sin_addr.s_addr = INADDR_ANY; + + if (bind(socket_fd,(struct sockaddr *)(&sin), + sizeof(struct sockaddr_in)) < 0) + { + fprintf (stderr,"%s: cannot bind to port %d\n", + program_name,port); + exit(1); + } + + if (listen(socket_fd,5) < 0) + { + fprintf (stderr,"%s: error listening on socket\n", + program_name); + exit(1); + }; +} + +#define NUM_EVENTC 2 +static void +enable_device(GxidDevice *dev) +{ + XEventClass xevc[NUM_EVENTC]; + int num_eventc = NUM_EVENTC; + int i,j; + + if (!dev->xdevice) + { + if (dev->ispointer) return; + + dev->xdevice = XOpenDevice(dpy, dev->id); + if (!dev->xdevice) return; + + DeviceMotionNotify (dev->xdevice, dev->motionnotify_type, + xevc[0]); + ChangeDeviceNotify (dev->xdevice, dev->changenotify_type, + xevc[1]); + + /* compress out zero event classes */ + for (i=0,j=0;i<NUM_EVENTC;i++) + { + if (xevc[i]) { + xevc[j] = xevc[i]; + j++; + } + } + num_eventc = j; + + XSelectExtensionEvent (dpy, root_window, xevc, num_eventc); + } +} + +/* switch the core pointer from whatever it is now to something else, + return true on success, false otherwise */ +static int +switch_core_pointer() +{ + GxidDevice *old_pointer = 0; + GxidDevice *new_pointer = 0; + int result; + int i; + + for (i=0;i<num_devices;i++) + { + if (devices[i]->ispointer) + old_pointer = devices[i]; + else + if (!new_pointer && !devices[i]->exclusive) + new_pointer = devices[i]; + } + + if (!old_pointer || !new_pointer) + return 0; + +#ifdef DEBUG_EVENTS + fprintf(stderr,"gxid: Switching core from %ld to %ld\n", + old_pointer->id,new_pointer->id); +#endif + result = XChangePointerDevice(dpy,new_pointer->xdevice, 0, 1); + if (result != Success) + { + fprintf(stderr,"gxid: Error %d switching core from %ld to %ld\n", + result, old_pointer->id, new_pointer->id); + } + else + { + new_pointer->ispointer = 1; + old_pointer->ispointer = 0; + if (!old_pointer->xdevice) + enable_device(old_pointer); + } + + return 1; +} + +void +disable_device(GxidDevice *dev) +{ + if (dev->xdevice) + { + if (dev->ispointer) + return; + XCloseDevice(dpy,dev->xdevice); + dev->xdevice = 0; + } +} + +GxidDevice * +init_device(XDeviceInfo *xdevice) +{ + GxidDevice *dev = (GxidDevice *)malloc(sizeof(GxidDevice)); + XAnyClassPtr class; + int num_axes, i; + + dev->id = xdevice->id; + dev->exclusive = 0; + dev->xdevice = NULL; + + dev->ispointer = (xdevice->use == IsXPointer); + + /* step through the classes */ + + num_axes = 0; + class = xdevice->inputclassinfo; + for (i=0;i<xdevice->num_classes;i++) + { + if (class->class == ValuatorClass) + { + XValuatorInfo *xvi = (XValuatorInfo *)class; + num_axes = xvi->num_axes; + } + class = (XAnyClassPtr)(((char *)class) + class->length); + } + + /* return NULL if insufficient axes */ + if (num_axes < 2) + { + free((void *)dev); + return NULL; + } + + if (!dev->ispointer) + enable_device(dev); + return dev; +} + +void +init_xinput() +{ + char **extensions; + XDeviceInfo *xdevices; + int num_xdevices; + int num_extensions; + int i; + + extensions = XListExtensions(dpy, &num_extensions); + for (i = 0; i < num_extensions && + (strcmp(extensions[i], "XInputExtension") != 0); i++); + XFreeExtensionList(extensions); + if (i == num_extensions) /* XInput extension not found */ + { + fprintf(stderr,"XInput extension not found\n"); + exit(1); + } + + xdevices = XListInputDevices(dpy, &num_xdevices); + devices = (GxidDevice **)malloc(num_xdevices * sizeof(GxidDevice *)); + + num_devices = 0; + for(i=0; i<num_xdevices; i++) + { + GxidDevice *dev = init_device(&xdevices[i]); + if (dev) + devices[num_devices++] = dev; + } + XFreeDeviceList(xdevices); +} + +/* If this routine needs fixing, the corresponding routine + in gdkinputgxi.h will need it too. */ + +Window +gxi_find_root_child(Display *dpy, Window w) +{ + Window root,parent; + Window *children; + int nchildren; + + parent = w; + do + { + w = parent; + XQueryTree(dpy,w,&root,&parent,&children,&nchildren); + if (children) XFree(children); + } + while (parent != root); + + return w; +} + +int +handle_claim_device(GxidClaimDevice *msg) +{ + int i,j; + XID devid = ntohl(msg->device); + XID winid = ntohl(msg->window); + int exclusive = ntohl(msg->exclusive); + GxidDevice *device = NULL; + GxidWindow *window = NULL; + +#ifdef DEBUG_CLIENTS + fprintf(stderr,"device %ld claimed (window 0x%lx)\n",devid,winid); +#endif + + for (i=0;i<num_devices;i++) + { + if (devices[i]->id == devid) + { + device = devices[i]; + break; + } + } + if (!device) + { + fprintf(stderr,"%s: Unknown device id %ld\n",program_name,devid); + return GXID_RETURN_ERROR; + } + + if (device->exclusive) + { + /* already in use */ + fprintf(stderr, + "%s: Device %ld already claimed in exclusive mode\n", + program_name,devid); + return GXID_RETURN_ERROR; + } + + if (exclusive) + { + for (i=0;i<num_windows;i++) + { + for (j=0;j<windows[i]->num_devices;j++) + if (windows[i]->devices[j]->id == devid) + { + /* already in use */ + fprintf(stderr, + "%s: Can't establish exclusive use of device %ld\n", + program_name,devid); + return GXID_RETURN_ERROR; + } + } + if (device->ispointer) + if (!switch_core_pointer()) + { + fprintf(stderr, + "%s: Can't free up core pointer %ld\n", + program_name,devid); + return GXID_RETURN_ERROR; + } + + device->exclusive = 1; + disable_device(device); + XSelectInput(dpy,winid,StructureNotifyMask); + } + else /* !exclusive */ + { + /* FIXME: this is a bit improper. We probably should do this only + when a window is first claimed. But we might be fooled if + an old client died without releasing it's windows. So until + we look for client-window closings, do it here + + (We do look for closings now...) + */ + + XSelectInput(dpy,winid,EnterWindowMask|StructureNotifyMask); + } + + for (i=0;i<num_windows;i++) + { + if (windows[i]->xwindow == winid) + { + window = windows[i]; + break; + } + } + + /* Create window structure if no devices have been previously + claimed on it */ + if (!window) + { + num_windows++; + windows = (GxidWindow **)realloc(windows, + sizeof(GxidWindow*)*num_windows); + window = (GxidWindow *)malloc(sizeof(GxidWindow)); + windows[num_windows-1] = window; + + window->xwindow = winid; + window->root_child = gxi_find_root_child(dpy,winid); + window->num_devices = 0; + window->devices = 0; + } + + + for (i=0;i<window->num_devices;i++) + { + if (window->devices[i] == device) + return GXID_RETURN_OK; + } + + window->num_devices++; + window->devices = (GxidDevice **)realloc(window->devices, + sizeof(GxidDevice*)*num_devices); + /* we need add the device to the window */ + window->devices[i] = device; + + return GXID_RETURN_OK; +} + +int +handle_release_device(GxidReleaseDevice *msg) +{ + int i,j; + XID devid = ntohl(msg->device); + XID winid = ntohl(msg->window); + + GxidDevice *device = NULL; + +#ifdef DEBUG_CLIENTS + fprintf(stderr,"device %ld released (window 0x%lx)\n",devid,winid); +#endif + + for (i=0;i<num_devices;i++) + { + if (devices[i]->id == devid) + { + device = devices[i]; + break; + } + } + if (!device) + { + fprintf(stderr,"%s: Unknown device id %ld\n",program_name,devid); + return GXID_RETURN_ERROR; + } + + for (i=0;i<num_windows;i++) + { + GxidWindow *w = windows[i]; + + if (w->xwindow == winid) + for (j=0;j<w->num_devices;j++) + if (w->devices[j]->id == devid) + { + if (j<w->num_devices-1) + w->devices[j] = w->devices[w->num_devices-1]; + w->num_devices--; + + if (w->num_devices == 0) + { + if (i<num_windows-1) + windows[i] = windows[num_windows-1]; + num_windows--; + + free((void *)w); + /* FIXME: should we deselect input? But what + what if window is already destroyed */ + } + + if (device->exclusive) + { + device->exclusive = 0; + enable_device(device); + } + return GXID_RETURN_OK; + } + } + + /* device/window combination not found */ + fprintf(stderr, + "%s: Device %ld not claimed for window 0x%lx\n", + program_name,devid,winid); + return GXID_RETURN_ERROR; +} + +void +handle_connection() +{ + GxidMessage msg; + GxidU32 type; + int length; + GxidI32 retval; + + int conn_fd; + struct sockaddr_in sin; + int sin_length; + int count; + + sin_length = sizeof(struct sockaddr_in); + conn_fd = accept(socket_fd,(struct sockaddr *)&sin,&sin_length); + if (conn_fd < 0) + { + fprintf(stderr,"%s: Error accepting connection\n", + program_name); + exit(1); + } + + /* read type and length of message */ + + count = read(conn_fd,(char *)&msg,2*sizeof(GxidU32)); + if (count != 2*sizeof(GxidU32)) + { + fprintf(stderr,"%s: Error reading message header\n", + program_name); + close(conn_fd); + return; + } + type = ntohl(msg.any.type); + length = ntohl(msg.any.length); + + /* read rest of message */ + + if (length > sizeof(GxidMessage)) + { + fprintf(stderr,"%s: Bad message length\n", + program_name); + close(conn_fd); + return; + } + + count = read(conn_fd,2*sizeof(GxidU32) + (char *)&msg, + length - 2*sizeof(GxidU32)); + if (count != length - 2*sizeof(GxidU32)) + { + fprintf(stderr,"%s: Error reading message body\n", + program_name); + close(conn_fd); + return; + } + + switch (type) + { + case GXID_CLAIM_DEVICE: + retval = handle_claim_device((GxidClaimDevice *)&msg); + break; + case GXID_RELEASE_DEVICE: + retval = handle_release_device((GxidReleaseDevice *)&msg); + break; + default: + fprintf(stderr,"%s: Unknown message type: %ld (ignoring)\n", + program_name,type); + close(conn_fd); + return; + } + + count = write(conn_fd,&retval,sizeof(GxidI32)); + if (count != sizeof(GxidI32)) + { + fprintf(stderr,"%s: Error writing return code\n", + program_name); + } + + close(conn_fd); +} + +void +handle_motion_notify(XDeviceMotionEvent *event) +{ + int i,j; + GxidDevice *old_device = NULL; + GxidDevice *new_device = NULL; + Window w, root, child; + int root_x, root_y, x, y, mask; + + for (j=0;j<num_devices;j++) + { + if (devices[j]->ispointer) + old_device = devices[j]; + if (devices[j]->id == event->deviceid) + new_device = devices[j]; + } + + if (new_device && !new_device->exclusive && !new_device->ispointer) + { + /* make sure we aren't stealing the pointer back from a slow + client */ + child = root_window; + do + { + w = child; + /* FIXME: this fails disasterously if child vanishes between + calls. (Which is prone to happening since we get events + on root just as the client exits) */ + + XQueryPointer(dpy,w,&root,&child,&root_x,&root_y, + &x,&y,&mask); + } + while (child != None); + + for (i=0;i<num_windows;i++) + if (windows[i]->xwindow == w) + for (j=0;j<windows[i]->num_devices;j++) + if (windows[i]->devices[j] == new_device) + return; + + /* FIXME: do something smarter with axes */ + XChangePointerDevice(dpy,new_device->xdevice, 0, 1); + new_device->ispointer = 1; + + old_device->ispointer = 0; + if (!old_device->xdevice) + enable_device(old_device); + } +} + +void +handle_change_notify(XChangeDeviceNotifyEvent *event) +{ + int j; + GxidDevice *old_device = NULL; + GxidDevice *new_device = NULL; + + + for (j=0;j<num_devices;j++) + { + if (devices[j]->ispointer) + old_device = devices[j]; + if (devices[j]->id == event->deviceid) + new_device = devices[j]; + } + +#ifdef DEBUG_EVENTS + fprintf(stderr,"gxid: ChangeNotify event; old = %ld; new = %ld\n", + old_device->id, new_device->id); +#endif + + if (old_device != new_device) + { + new_device->ispointer = 1; + + old_device->ispointer = 0; + if (!old_device->xdevice) + enable_device(old_device); + } +} + +void +handle_enter_notify(XEnterWindowEvent *event, GxidWindow *window) +{ + int i; + GxidDevice *old_pointer = NULL; + for (i=0;i<num_devices;i++) + { + if (devices[i]->ispointer) + { + old_pointer = devices[i]; + break; + } + } + +#ifdef DEBUG_EVENTS + fprintf(stderr,"gxid: Enter event; oldpointer = %ld\n", + old_pointer->id); +#endif + + if (old_pointer) + for (i=0;i<window->num_devices;i++) + { + if (window->devices[i] == old_pointer) + { + switch_core_pointer(); + break; + } + } +} + +void +handle_destroy_notify(XDestroyWindowEvent *event) +{ + int i,j; + + for (i=0;i<num_windows;i++) + if (windows[i]->xwindow == event->window) + { + GxidWindow *w = windows[i]; + + for (j=0;j<w->num_devices;j++) + { +#ifdef DEBUG_CLIENTS + fprintf(stderr,"device %ld released on destruction of window 0x%lx.\n", + w->devices[j]->id,w->xwindow); +#endif + + if (w->devices[j]->exclusive) + { + w->devices[j]->exclusive = 0; + enable_device(devices[j]); + } + } + + if (i<num_windows-1) + windows[i] = windows[num_windows-1]; + num_windows--; + + if (w->devices) + free((void *)w->devices); + free((void *)w); + /* FIXME: should we deselect input? But what + what if window is already destroyed */ + + return; + } +} + +void +handle_xevent() +{ + int i; + XEvent event; + + XNextEvent (dpy, &event); + +#ifdef DEBUG_EVENTS + fprintf(stderr,"Event - type = %d; window = 0x%lx\n", + event.type,event.xany.window); +#endif + + if (event.type == ConfigureNotify) + { +#ifdef DEBUG_EVENTS + XConfigureEvent *xce = (XConfigureEvent *)&event; + fprintf(stderr," configureNotify: window = 0x%lx\n",xce->window); +#endif + } + else if (event.type == EnterNotify) + { + /* pointer entered a claimed window */ + for (i=0;i<num_windows;i++) + { + if (event.xany.window == windows[i]->xwindow) + handle_enter_notify((XEnterWindowEvent *)&event,windows[i]); + } + } + else if (event.type == DestroyNotify) + { + /* A claimed window was destroyed */ + for (i=0;i<num_windows;i++) + { + if (event.xany.window == windows[i]->xwindow) + handle_destroy_notify((XDestroyWindowEvent *)&event); + } + } + else + for (i=0;i<num_devices;i++) + { + if (event.type == devices[i]->motionnotify_type) + { + handle_motion_notify((XDeviceMotionEvent *)&event); + break; + } + else if (event.type == devices[i]->changenotify_type) + { + handle_change_notify((XChangeDeviceNotifyEvent *)&event); + break; + } + } +} + +void +usage() +{ + fprintf(stderr,"Usage: %s [-d display] [-p --gxid-port port]\n", + program_name); + exit(1); +} + +int +main(int argc, char **argv) +{ + int i; + char *display_name = NULL; + fd_set readfds; + + program_name = argv[0]; + + for (i=1;i<argc;i++) + { + if (!strcmp(argv[i],"-d")) + { + if (++i >= argc) usage(); + display_name = argv[i]; + } + else if (!strcmp(argv[i],"--gxid-port") || + !strcmp(argv[i],"-p")) + { + if (++i >= argc) usage(); + port = atoi(argv[i]); + break; + } + else + usage(); + } + + if (!port) + { + char *t = getenv("GXID_PORT"); + if (t) + port = atoi(t); + else + port = 6951; + } + /* set up a signal handler so we can clean up if killed */ + + signal(SIGTERM,handler); + signal(SIGINT,handler); + + /* initialize the X connection */ + + dpy = XOpenDisplay (display_name); + if (!dpy) + { + fprintf (stderr, "%s: unable to open display '%s'\n", + program_name, XDisplayName (display_name)); + exit (1); + } + + root_window = DefaultRootWindow(dpy); + + /* We'll want to do this in the future if we are to support + gxid monitoring visibility information for clients */ +#if 0 + XSelectInput(dpy,root_window,SubstructureNotifyMask); +#endif + init_xinput(); + + /* set up our server connection */ + + init_socket(); + + /* main loop */ + + if (XPending(dpy)) /* this seems necessary to get things + in sync */ + handle_xevent(); + while (1) + { + + FD_ZERO(&readfds); + FD_SET(ConnectionNumber(dpy),&readfds); + FD_SET(socket_fd,&readfds); + + if (select(8*sizeof(readfds),&readfds, + (fd_set *)0,(fd_set *)0, (struct timeval *)0) < 0) + { + fprintf(stderr,"Error in select\n"); + exit(1); + } + + if (FD_ISSET(socket_fd,&readfds)) + handle_connection(socket_fd); + + while (XPending(dpy)) + handle_xevent(); + } + + XCloseDisplay (dpy); + exit (0); +} diff --git a/gdk/gxid_lib.c b/gdk/gxid_lib.c new file mode 100644 index 000000000..357b76451 --- /dev/null +++ b/gdk/gxid_lib.c @@ -0,0 +1,116 @@ +/* + * gxid version 0.3 + * + * Copyright 1997 Owen Taylor <owt1@cornell.edu> +*/ + +#include "../config.h" + +#ifdef XINPUT_GXI + +#include <stdio.h> +#include <unistd.h> +#include <sys/time.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <netdb.h> + +#include "gxid_lib.h" + +/* handles mechanics of communicating with a client */ +static int +gxid_send_message(char *host, int port, GxidMessage *msg) +{ + int socket_fd; + struct sockaddr_in sin; + int count; + GxidI32 retval; + struct hostent *he; + + if (!port) port = 6951; + + if (!host || strcmp(host,"localhost") ) + { + /* looking it up as localhost can be _SLOW_ on ppp systems */ + /* FIXME: Could localhost be anything other than loopback? */ + host = "127.0.0.1"; + } + + he = gethostbyname(host); + if (!he) + { + fprintf(stderr,"gxid_lib: error looking up %s\n",host); + return GXID_RETURN_ERROR; + } + + sin.sin_family = he->h_addrtype; + sin.sin_port = htons(port); + memcpy(&sin.sin_addr,he->h_addr_list[0],he->h_length); + + socket_fd = socket(AF_INET,SOCK_STREAM,0); + if (socket_fd < 0) + { + fprintf(stderr,"gxid_lib: can't get socket"); + return GXID_RETURN_ERROR; + } + + if (connect(socket_fd, (struct sockaddr *)&sin, + sizeof sin) < 0) + { + fprintf(stderr,"gxid_lib: can't connect to %s:%d\n",host,port); + close(socket_fd); + return GXID_RETURN_ERROR; + } + + count = write(socket_fd,(char *)msg,ntohl(msg->any.length)); + if (count != ntohl(msg->any.length)) + { + fprintf(stderr,"gxid_lib: error writing"); + close(socket_fd); + return GXID_RETURN_ERROR; + } + + /* now read the return code */ + count = read(socket_fd,(char *)&retval,sizeof(GxidI32)); + if (count != sizeof(GxidI32)) + { + fprintf(stderr,"gxid_lib: error reading return code"); + close(socket_fd); + return GXID_RETURN_ERROR; + } + + close (socket_fd); + return ntohl(retval); +} + +/* claim a device. If exclusive, device is claimed exclusively */ +int +gxid_claim_device(char *host, int port, GxidU32 device, GxidU32 window, + int exclusive) +{ + GxidClaimDevice msg; + msg.type = htonl(GXID_CLAIM_DEVICE); + msg.length = htonl(sizeof(GxidClaimDevice)); + msg.device = htonl(device); + msg.window = htonl(window); + msg.exclusive = htonl(exclusive); + + return gxid_send_message(host,port,(GxidMessage *)&msg); +} + +/* release a device/window pair */ +int +gxid_release_device(char *host, int port, GxidU32 device, GxidU32 window) +{ + GxidReleaseDevice msg; + msg.type = htonl(GXID_RELEASE_DEVICE); + msg.length = htonl(sizeof(GxidReleaseDevice)); + msg.device = htonl(device); + msg.window = htonl(window); + + return gxid_send_message(host,port,(GxidMessage *)&msg); +} + +#endif /* XINPUT_GXI */ + diff --git a/gdk/gxid_lib.h b/gdk/gxid_lib.h new file mode 100644 index 000000000..6a7103bbe --- /dev/null +++ b/gdk/gxid_lib.h @@ -0,0 +1,6 @@ +#include "gxid_proto.h" + +int gxid_claim_device(char *host, int port, + GxidU32 device, GxidU32 window, int exclusive); +int gxid_release_device(char *host, int port, GxidU32 device, + GxidU32 window); diff --git a/gdk/gxid_proto.h b/gdk/gxid_proto.h new file mode 100644 index 000000000..24959b806 --- /dev/null +++ b/gdk/gxid_proto.h @@ -0,0 +1,39 @@ +#define GXID_CLAIM_DEVICE 1 +#define GXID_RELEASE_DEVICE 2 + +#define GXID_RETURN_OK 0 +#define GXID_RETURN_ERROR -1 + +typedef struct GxidClaimDevice_ GxidClaimDevice; +typedef struct GxidReleaseDevice_ GxidReleaseDevice; +typedef struct GxidMessageAny_ GxidMessageAny; +typedef union GxidMessage_ GxidMessage; + +typedef unsigned long GxidU32; +typedef long GxidI32; + +struct GxidClaimDevice_ { + GxidU32 type; + GxidU32 length; + GxidU32 device; + GxidU32 window; + GxidU32 exclusive; +}; + +struct GxidReleaseDevice_ { + GxidU32 type; + GxidU32 length; + GxidU32 device; + GxidU32 window; +}; + +struct GxidMessageAny_ { + GxidU32 type; + GxidU32 length; +}; + +union GxidMessage_ { + GxidMessageAny any; + GxidClaimDevice claim; + GxidReleaseDevice release; +}; diff --git a/gdk/makecursors b/gdk/makecursors new file mode 100755 index 000000000..664776a2b --- /dev/null +++ b/gdk/makecursors @@ -0,0 +1,5 @@ +#!/bin/sh + +sed -f makecursors.sed $1 > .makecursors.tmp +awk '{printf "%s = %s,\n", $1, $2}' .makecursors.tmp +rm .makecursors.tmp diff --git a/gdk/makecursors.sed b/gdk/makecursors.sed new file mode 100644 index 000000000..107d13f8d --- /dev/null +++ b/gdk/makecursors.sed @@ -0,0 +1,3 @@ +/define/ ! d +/define/ y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/ +s/^.*XC_/GDK_/g diff --git a/gdk/makekeysyms b/gdk/makekeysyms new file mode 100755 index 000000000..40b49d4e8 --- /dev/null +++ b/gdk/makekeysyms @@ -0,0 +1,5 @@ +#!/bin/sh + +sed -f makekeysyms.sed $1 > .makekeysms.tmp +awk '{printf "#define %s %s\n", $1, $2}' .makekeysms.tmp +rm .makekeysms.tmp diff --git a/gdk/makekeysyms.sed b/gdk/makekeysyms.sed new file mode 100644 index 000000000..bafbf76c0 --- /dev/null +++ b/gdk/makekeysyms.sed @@ -0,0 +1,3 @@ +/define/ ! d +s/^.*XK_/GDK_/g +s/0X/0x/g diff --git a/gdk/x11/gdkcolor-x11.c b/gdk/x11/gdkcolor-x11.c new file mode 100644 index 000000000..5e66f089b --- /dev/null +++ b/gdk/x11/gdkcolor-x11.c @@ -0,0 +1,718 @@ +/* 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 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include <X11/Xlib.h> +#include "gdk.h" +#include "gdkprivate.h" + + +static gint gdk_colormap_match_color (GdkColormap *cmap, + GdkColor *color, + const gchar *available); +static void gdk_colormap_add (GdkColormap *cmap); +static void gdk_colormap_remove (GdkColormap *cmap); +static guint gdk_colormap_hash (Colormap *cmap); +static gint gdk_colormap_cmp (Colormap *a, + Colormap *b); + +static GHashTable *colormap_hash = NULL; + + +GdkColormap* +gdk_colormap_new (GdkVisual *visual, + gint private_cmap) +{ + GdkColormap *colormap; + GdkColormapPrivate *private; + Visual *xvisual; + XColor default_colors[256]; + int size; + int i; + + g_return_val_if_fail (visual != NULL, NULL); + + private = g_new (GdkColormapPrivate, 1); + colormap = (GdkColormap*) private; + + private->xdisplay = gdk_display; + private->visual = visual; + private->next_color = 0; + private->ref_count = 1; + xvisual = ((GdkVisualPrivate*) visual)->xvisual; + + switch (visual->type) + { + case GDK_VISUAL_GRAYSCALE: + case GDK_VISUAL_PSEUDO_COLOR: + private->private_val = private_cmap; + private->xcolormap = XCreateColormap (private->xdisplay, gdk_root_window, + xvisual, (private_cmap) ? (AllocAll) : (AllocNone)); + + if (private_cmap) + { + for (i = 0; i < 256; i++) + default_colors[i].pixel = i; + + XQueryColors (private->xdisplay, + DefaultColormap (private->xdisplay, gdk_screen), + default_colors, visual->colormap_size); + + for (i = 0; i < visual->colormap_size; i++) + { + colormap->colors[i].pixel = default_colors[i].pixel; + colormap->colors[i].red = default_colors[i].red; + colormap->colors[i].green = default_colors[i].green; + colormap->colors[i].blue = default_colors[i].blue; + } + + gdk_colormap_change (colormap, visual->colormap_size); + } + break; + + case GDK_VISUAL_DIRECT_COLOR: + private->private_val = TRUE; + private->xcolormap = XCreateColormap (private->xdisplay, gdk_root_window, + xvisual, AllocAll); + + size = 1 << visual->red_prec; + for (i = 0; i < size; i++) + colormap->colors[i].red = i * 65535 / (size - 1); + + size = 1 << visual->green_prec; + for (i = 0; i < size; i++) + colormap->colors[i].green = i * 65535 / (size - 1); + + size = 1 << visual->blue_prec; + for (i = 0; i < size; i++) + colormap->colors[i].blue = i * 65535 / (size - 1); + + gdk_colormap_change (colormap, visual->colormap_size); + break; + + case GDK_VISUAL_STATIC_GRAY: + case GDK_VISUAL_STATIC_COLOR: + case GDK_VISUAL_TRUE_COLOR: + private->private_val = FALSE; + private->xcolormap = XCreateColormap (private->xdisplay, gdk_root_window, + xvisual, AllocNone); + break; + } + + gdk_colormap_add (colormap); + + return colormap; +} + +void +gdk_colormap_real_destroy (GdkColormap *colormap) +{ + GdkColormapPrivate *private = (GdkColormapPrivate*) colormap; + + g_return_if_fail (colormap != NULL); + + if (private->ref_count > 0) + return; + + gdk_colormap_remove (colormap); + XFreeColormap (private->xdisplay, private->xcolormap); + g_free (colormap); +} + +void +gdk_colormap_destroy (GdkColormap *colormap) +{ + gdk_colormap_unref (colormap); +} + +GdkColormap* +gdk_colormap_ref (GdkColormap *cmap) +{ + GdkColormapPrivate *private = (GdkColormapPrivate *)cmap; + g_return_val_if_fail (cmap != NULL, NULL); + + private->ref_count += 1; + return cmap; +} + +void +gdk_colormap_unref (GdkColormap *cmap) +{ + GdkColormapPrivate *private = (GdkColormapPrivate *)cmap; + g_return_if_fail (cmap != NULL); + + private->ref_count -= 1; + if (private->ref_count == 0) + gdk_colormap_real_destroy (cmap); +} + +GdkColormap* +gdk_colormap_get_system (void) +{ + static GdkColormap *colormap = NULL; + GdkColormapPrivate *private; + XColor xpalette[256]; + gint i; + + if (!colormap) + { + private = g_new (GdkColormapPrivate, 1); + colormap = (GdkColormap*) private; + + private->xdisplay = gdk_display; + private->xcolormap = DefaultColormap (gdk_display, gdk_screen); + private->visual = gdk_visual_get_system (); + private->private_val = FALSE; + private->next_color = 0; + private->ref_count = 1; + + for (i = 0; i < 256; i++) + { + xpalette[i].pixel = i; + xpalette[i].red = 0; + xpalette[i].green = 0; + xpalette[i].blue = 0; + } + + XQueryColors (gdk_display, private->xcolormap, xpalette, 256); + + for (i = 0; i < 256; i++) + { + colormap->colors[i].pixel = xpalette[i].pixel; + colormap->colors[i].red = xpalette[i].red; + colormap->colors[i].green = xpalette[i].green; + colormap->colors[i].blue = xpalette[i].blue; + } + + gdk_colormap_add (colormap); + } + + return colormap; +} + +gint +gdk_colormap_get_system_size (void) +{ + return DisplayCells (gdk_display, gdk_screen); +} + +void +gdk_colormap_change (GdkColormap *colormap, + gint ncolors) +{ + GdkColormapPrivate *private; + GdkVisual *visual; + XColor palette[256]; + gint shift; + int max_colors; + int size; + int i; + + g_return_if_fail (colormap != NULL); + + private = (GdkColormapPrivate*) colormap; + switch (private->visual->type) + { + case GDK_VISUAL_GRAYSCALE: + case GDK_VISUAL_PSEUDO_COLOR: + for (i = 0; i < ncolors; i++) + { + palette[i].pixel = colormap->colors[i].pixel; + palette[i].red = colormap->colors[i].red; + palette[i].green = colormap->colors[i].green; + palette[i].blue = colormap->colors[i].blue; + palette[i].flags = DoRed | DoGreen | DoBlue; + } + + XStoreColors (private->xdisplay, private->xcolormap, palette, ncolors); + private->next_color = MAX (private->next_color, ncolors); + break; + + case GDK_VISUAL_DIRECT_COLOR: + visual = private->visual; + + shift = visual->red_shift; + max_colors = 1 << visual->red_prec; + size = (ncolors < max_colors) ? (ncolors) : (max_colors); + + for (i = 0; i < size; i++) + { + palette[i].pixel = i << shift; + palette[i].red = colormap->colors[i].red; + palette[i].flags = DoRed; + } + + XStoreColors (private->xdisplay, private->xcolormap, palette, size); + + shift = visual->green_shift; + max_colors = 1 << visual->green_prec; + size = (ncolors < max_colors) ? (ncolors) : (max_colors); + + for (i = 0; i < size; i++) + { + palette[i].pixel = i << shift; + palette[i].green = colormap->colors[i].green; + palette[i].flags = DoGreen; + } + + XStoreColors (private->xdisplay, private->xcolormap, palette, size); + + shift = visual->blue_shift; + max_colors = 1 << visual->blue_prec; + size = (ncolors < max_colors) ? (ncolors) : (max_colors); + + for (i = 0; i < size; i++) + { + palette[i].pixel = i << shift; + palette[i].blue = colormap->colors[i].blue; + palette[i].flags = DoBlue; + } + + XStoreColors (private->xdisplay, private->xcolormap, palette, size); + break; + + default: + break; + } +} + +void +gdk_colors_store (GdkColormap *colormap, + GdkColor *colors, + gint ncolors) +{ + gint i; + + for (i = 0; i < ncolors; i++) + { + colormap->colors[i].pixel = colors[i].pixel; + colormap->colors[i].red = colors[i].red; + colormap->colors[i].green = colors[i].green; + colormap->colors[i].blue = colors[i].blue; + } + + gdk_colormap_change (colormap, ncolors); +} + +gint +gdk_colors_alloc (GdkColormap *colormap, + gint contiguous, + gulong *planes, + gint nplanes, + gulong *pixels, + gint npixels) +{ + GdkColormapPrivate *private; + gint return_val; + + g_return_val_if_fail (colormap != NULL, 0); + + private = (GdkColormapPrivate*) colormap; + + return_val = XAllocColorCells (private->xdisplay, private->xcolormap, + contiguous, planes, nplanes, pixels, npixels); + + return return_val; +} + +void +gdk_colors_free (GdkColormap *colormap, + gulong *pixels, + gint npixels, + gulong planes) +{ + GdkColormapPrivate *private; + + g_return_if_fail (colormap != NULL); + + private = (GdkColormapPrivate*) colormap; + + XFreeColors (private->xdisplay, private->xcolormap, + pixels, npixels, planes); +} + +gint +gdk_color_white (GdkColormap *colormap, + GdkColor *color) +{ + gint return_val; + + g_return_val_if_fail (colormap != NULL, FALSE); + + if (color) + { + color->pixel = WhitePixel (gdk_display, gdk_screen); + color->red = 65535; + color->green = 65535; + color->blue = 65535; + + return_val = gdk_color_alloc (colormap, color); + } + else + return_val = FALSE; + + return return_val; +} + +gint +gdk_color_black (GdkColormap *colormap, + GdkColor *color) +{ + gint return_val; + + g_return_val_if_fail (colormap != NULL, FALSE); + + if (color) + { + color->pixel = BlackPixel (gdk_display, gdk_screen); + color->red = 0; + color->green = 0; + color->blue = 0; + + return_val = gdk_color_alloc (colormap, color); + } + else + return_val = FALSE; + + return return_val; +} + +gint +gdk_color_parse (const gchar *spec, + GdkColor *color) +{ + Colormap xcolormap; + XColor xcolor; + gint return_val; + + g_return_val_if_fail (spec != NULL, FALSE); + g_return_val_if_fail (color != NULL, FALSE); + + xcolormap = DefaultColormap (gdk_display, gdk_screen); + + if (XParseColor (gdk_display, xcolormap, spec, &xcolor)) + { + return_val = TRUE; + color->red = xcolor.red; + color->green = xcolor.green; + color->blue = xcolor.blue; + } + else + return_val = FALSE; + + return return_val; +} + +gint +gdk_color_alloc (GdkColormap *colormap, + GdkColor *color) +{ + GdkColormapPrivate *private; + GdkVisual *visual; + XColor xcolor; + gchar available[256]; + gint available_init; + gint return_val; + gint i, index; + + g_return_val_if_fail (colormap != NULL, FALSE); + g_return_val_if_fail (color != NULL, FALSE); + + xcolor.red = color->red; + xcolor.green = color->green; + xcolor.blue = color->blue; + xcolor.pixel = color->pixel; + xcolor.flags = DoRed | DoGreen | DoBlue; + + return_val = FALSE; + private = (GdkColormapPrivate*) colormap; + + switch (private->visual->type) + { + case GDK_VISUAL_GRAYSCALE: + case GDK_VISUAL_PSEUDO_COLOR: + if (private->private_val) + { + if (private->next_color > 255) + { + for (i = 0; i < 256; i++) + available[i] = TRUE; + + index = gdk_colormap_match_color (colormap, color, available); + if (index != -1) + { + available[index] = FALSE; + *color = colormap->colors[index]; + return_val = TRUE; + } + else + { + return_val = FALSE; + } + } + else + { + xcolor.pixel = 255 - private->next_color; + color->pixel = xcolor.pixel; + private->next_color += 1; + + XStoreColor (private->xdisplay, private->xcolormap, &xcolor); + return_val = TRUE; + } + } + else + { + available_init = 1; + + while (1) + { + if (XAllocColor (private->xdisplay, private->xcolormap, &xcolor)) + { + color->pixel = xcolor.pixel; + color->red = xcolor.red; + color->green = xcolor.green; + color->blue = xcolor.blue; + + colormap->colors[color->pixel] = *color; + + return_val = TRUE; + break; + } + else + { + if (available_init) + { + available_init = 0; + for (i = 0; i < 256; i++) + available[i] = TRUE; + } + + index = gdk_colormap_match_color (colormap, color, available); + if (index != -1) + { + available[index] = FALSE; + xcolor.red = colormap->colors[index].red; + xcolor.green = colormap->colors[index].green; + xcolor.blue = colormap->colors[index].blue; + } + else + { + return_val = FALSE; + break; + } + } + } + } + break; + + case GDK_VISUAL_DIRECT_COLOR: + visual = private->visual; + xcolor.pixel = (((xcolor.red >> (16 - visual->red_prec)) << visual->red_shift) + + ((xcolor.green >> (16 - visual->green_prec)) << visual->green_shift) + + ((xcolor.blue >> (16 - visual->blue_prec)) << visual->blue_shift)); + color->pixel = xcolor.pixel; + return_val = TRUE; + break; + + case GDK_VISUAL_STATIC_GRAY: + case GDK_VISUAL_STATIC_COLOR: + case GDK_VISUAL_TRUE_COLOR: + if (XAllocColor (private->xdisplay, private->xcolormap, &xcolor)) + { + color->pixel = xcolor.pixel; + return_val = TRUE; + } + else + return_val = FALSE; + break; + } + + return return_val; +} + +gint +gdk_color_change (GdkColormap *colormap, + GdkColor *color) +{ + GdkColormapPrivate *private; + XColor xcolor; + + g_return_val_if_fail (colormap != NULL, FALSE); + g_return_val_if_fail (color != NULL, FALSE); + + xcolor.pixel = color->pixel; + xcolor.red = color->red; + xcolor.green = color->green; + xcolor.blue = color->blue; + xcolor.flags = DoRed | DoGreen | DoBlue; + + private = (GdkColormapPrivate*) colormap; + XStoreColor (private->xdisplay, private->xcolormap, &xcolor); + + return TRUE; +} + +gint +gdk_color_equal (GdkColor *colora, + GdkColor *colorb) +{ + g_return_val_if_fail (colora != NULL, FALSE); + g_return_val_if_fail (colorb != NULL, FALSE); + + return ((colora->red == colorb->red) && + (colora->green == colorb->green) && + (colora->blue == colorb->blue)); +} + +GdkColormap* +gdkx_colormap_get (Colormap xcolormap) +{ + GdkColormap *colormap; + GdkColormapPrivate *private; + XColor xpalette[256]; + gint i; + + colormap = gdk_colormap_lookup (xcolormap); + if (colormap) + return colormap; + + if (xcolormap == DefaultColormap (gdk_display, gdk_screen)) + return gdk_colormap_get_system (); + + private = g_new (GdkColormapPrivate, 1); + colormap = (GdkColormap*) private; + + private->xdisplay = gdk_display; + private->xcolormap = xcolormap; + private->visual = NULL; + private->private_val = TRUE; + private->next_color = 0; + + for (i = 0; i < 256; i++) + { + xpalette[i].pixel = i; + xpalette[i].red = 0; + xpalette[i].green = 0; + xpalette[i].blue = 0; + } + + XQueryColors (gdk_display, private->xcolormap, xpalette, 256); + + for (i = 0; i < 256; i++) + { + colormap->colors[i].pixel = xpalette[i].pixel; + colormap->colors[i].red = xpalette[i].red; + colormap->colors[i].green = xpalette[i].green; + colormap->colors[i].blue = xpalette[i].blue; + } + + gdk_colormap_add (colormap); + + return colormap; +} + + +static gint +gdk_colormap_match_color (GdkColormap *cmap, + GdkColor *color, + const gchar *available) +{ + GdkColor *colors; + guint sum, max; + gint rdiff, gdiff, bdiff; + gint i, index; + + g_return_val_if_fail (cmap != NULL, 0); + g_return_val_if_fail (color != NULL, 0); + + colors = cmap->colors; + max = 3 * (65536); + index = -1; + + for (i = 0; i < 256; i++) + { + if ((!available) || (available && available[i])) + { + rdiff = (color->red - colors[i].red); + gdiff = (color->green - colors[i].green); + bdiff = (color->blue - colors[i].blue); + + sum = ABS (rdiff) + ABS (gdiff) + ABS (bdiff); + + if (sum < max) + { + index = i; + max = sum; + } + } + } + + return index; +} + + +GdkColormap* +gdk_colormap_lookup (Colormap xcolormap) +{ + GdkColormap *cmap; + + if (!colormap_hash) + return NULL; + + cmap = g_hash_table_lookup (colormap_hash, &xcolormap); + return cmap; +} + +static void +gdk_colormap_add (GdkColormap *cmap) +{ + GdkColormapPrivate *private; + + if (!colormap_hash) + colormap_hash = g_hash_table_new ((GHashFunc) gdk_colormap_hash, + (GCompareFunc) gdk_colormap_cmp); + + private = (GdkColormapPrivate*) cmap; + + g_hash_table_insert (colormap_hash, &private->xcolormap, cmap); +} + +static void +gdk_colormap_remove (GdkColormap *cmap) +{ + GdkColormapPrivate *private; + + if (!colormap_hash) + colormap_hash = g_hash_table_new ((GHashFunc) gdk_colormap_hash, + (GCompareFunc) gdk_colormap_cmp); + + private = (GdkColormapPrivate*) cmap; + + g_hash_table_remove (colormap_hash, &private->xcolormap); +} + +static guint +gdk_colormap_hash (Colormap *cmap) +{ + return *cmap; +} + +static gint +gdk_colormap_cmp (Colormap *a, + Colormap *b) +{ + return (*a == *b); +} diff --git a/gdk/x11/gdkcursor-x11.c b/gdk/x11/gdkcursor-x11.c new file mode 100644 index 000000000..22bfd250b --- /dev/null +++ b/gdk/x11/gdkcursor-x11.c @@ -0,0 +1,52 @@ +/* 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 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include <X11/Xlib.h> +#include <X11/cursorfont.h> +#include "gdk.h" +#include "gdkprivate.h" + + +GdkCursor* +gdk_cursor_new (GdkCursorType cursor_type) +{ + GdkCursorPrivate *private; + GdkCursor *cursor; + Cursor xcursor; + + xcursor = XCreateFontCursor (gdk_display, cursor_type); + private = g_new (GdkCursorPrivate, 1); + private->xdisplay = gdk_display; + private->xcursor = xcursor; + cursor = (GdkCursor*) private; + cursor->type = cursor_type; + + return cursor; +} + +void +gdk_cursor_destroy (GdkCursor *cursor) +{ + GdkCursorPrivate *private; + + g_return_if_fail (cursor != NULL); + + private = (GdkCursorPrivate *) cursor; + XFreeCursor (private->xdisplay, private->xcursor); + + g_free (private); +} diff --git a/gdk/x11/gdkfont-x11.c b/gdk/x11/gdkfont-x11.c new file mode 100644 index 000000000..e1b1e7254 --- /dev/null +++ b/gdk/x11/gdkfont-x11.c @@ -0,0 +1,379 @@ +/* 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 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include <X11/Xlib.h> +#include <X11/Xos.h> +#include "gdk.h" +#include "gdkprivate.h" + +GdkFont* +gdk_font_load (const gchar *font_name) +{ + GdkFont *font; + GdkFontPrivate *private; + + private = g_new (GdkFontPrivate, 1); + font = (GdkFont*) private; + + private->xdisplay = gdk_display; + private->xfont = XLoadQueryFont (private->xdisplay, font_name); + private->ref_count = 1; + + if (!private->xfont) + { + g_free (font); + return NULL; + } + else + { + font->type = GDK_FONT_FONT; + font->ascent = ((XFontStruct *) private->xfont)->ascent; + font->descent = ((XFontStruct *) private->xfont)->descent; + } + + gdk_xid_table_insert (&((XFontStruct *) private->xfont)->fid, font); + + return font; +} + +GdkFont* +gdk_fontset_load(gchar *fontset_name) +{ + GdkFont *font; + GdkFontPrivate *private; + XFontSet fontset; + gint missing_charset_count; + gchar **missing_charset_list; + gchar *def_string; + + private = g_new (GdkFontPrivate, 1); + font = (GdkFont*) private; + + private->xdisplay = gdk_display; + fontset = XCreateFontSet (gdk_display, fontset_name, + &missing_charset_list, &missing_charset_count, + &def_string); + + if (missing_charset_count) + { + g_print ("Missing charsets in FontSet creation"); + XFreeStringList (missing_charset_list); + } + + private->ref_count = 1; + + if (!fontset) + { + g_free (font); + return NULL; + } + else + { + XFontSetExtents *extent = XExtentsOfFontSet(fontset); + + private->xfont = fontset; + font->type = GDK_FONT_FONTSET; + /* how to define ascent and descent for fontset ??? */ + font->ascent = extent->max_logical_extent.height; + font->descent = font->ascent / 4 ; + } + return font; +} +void +gdk_font_free (GdkFont *font) +{ + GdkFontPrivate *private; + + g_return_if_fail (font != NULL); + + private = (GdkFontPrivate*) font; + + private->ref_count -= 1; + if (private->ref_count == 0) + { + gdk_xid_table_remove (((XFontStruct *) private->xfont)->fid); + XFreeFont (private->xdisplay, (XFontStruct *) private->xfont); + g_free (font); + } +} + +void +gdk_fontset_free (GdkFont *font) +{ + GdkFontPrivate *private; + + g_return_if_fail (font != NULL); + + private = (GdkFontPrivate*) font; + + private->ref_count -= 1; + if (private->ref_count == 0) + { + XFreeFontSet (private->xdisplay, (XFontSet) private->xfont); + g_free (font); + } +} + +GdkFont* +gdk_font_ref (GdkFont *font) +{ + GdkFontPrivate *private; + + g_return_val_if_fail (font != NULL, NULL); + + private = (GdkFontPrivate*) font; + private->ref_count += 1; + return font; +} + +gint +gdk_font_id (GdkFont *font) +{ + GdkFontPrivate *font_private; + + g_return_val_if_fail (font != NULL, 0); + + font_private = (GdkFontPrivate*) font; + + if (font->type == GDK_FONT_FONT) + { + return ((XFontStruct *) font_private->xfont)->fid; + } + else + { + return 0; + } +} + +gint +gdk_font_equal (GdkFont *fonta, + GdkFont *fontb) +{ + GdkFontPrivate *privatea; + GdkFontPrivate *privateb; + + g_return_val_if_fail (fonta != NULL, FALSE); + g_return_val_if_fail (fontb != NULL, FALSE); + + privatea = (GdkFontPrivate*) fonta; + privateb = (GdkFontPrivate*) fontb; + + if (fonta->type == GDK_FONT_FONT && fontb->type == GDK_FONT_FONT) + { + return (((XFontStruct *) privatea->xfont)->fid == + ((XFontStruct *) privateb->xfont)->fid); + } + else if (fonta->type == GDK_FONT_FONTSET && fontb->type == GDK_FONT_FONTSET) + { + /* how to compare two fontsets ?? by basename or XFontSet ?? */ + return (((XFontSet) privatea->xfont) == ((XFontSet) privateb->xfont)); + } + else + /* fontset != font */ + return 0; +} + +gint +gdk_string_width (GdkFont *font, + const gchar *string) +{ + GdkFontPrivate *font_private; + gint width; + XFontStruct *xfont; + XFontSet fontset; + + g_return_val_if_fail (font != NULL, -1); + g_return_val_if_fail (string != NULL, -1); + + font_private = (GdkFontPrivate*) font; + + switch (font->type) + { + case GDK_FONT_FONT: + xfont = (XFontStruct *) font_private->xfont; + if ((xfont->min_byte1 == 0) && (xfont->max_byte1 == 0)) + { + width = XTextWidth (xfont, string, strlen (string)); + } + else + { + width = XTextWidth16 (xfont, (XChar2b *) string, strlen (string) / 2); + } + break; + case GDK_FONT_FONTSET: + fontset = (XFontSet) font_private->xfont; + width = XmbTextEscapement (fontset, string, strlen(string)); + break; + default: + width = 0; + } + + return width; +} + +gint +gdk_text_width (GdkFont *font, + const gchar *text, + gint text_length) +{ + GdkFontPrivate *private; + gint width; + XFontStruct *xfont; + XFontSet fontset; + + g_return_val_if_fail (font != NULL, -1); + g_return_val_if_fail (text != NULL, -1); + + private = (GdkFontPrivate*) font; + + switch (font->type) + { + case GDK_FONT_FONT: + xfont = (XFontStruct *) private->xfont; + if ((xfont->min_byte1 == 0) && (xfont->max_byte1 == 0)) + { + width = XTextWidth (xfont, text, text_length); + } + else + { + width = XTextWidth16 (xfont, (XChar2b *) text, text_length / 2); + } + break; + case GDK_FONT_FONTSET: + fontset = (XFontSet) private->xfont; + width = XmbTextEscapement (fontset, text, text_length); + break; + default: + width = 0; + } + return width; +} + +/* Problem: What if a character is a 16 bits character ?? */ +gint +gdk_char_width (GdkFont *font, + gchar character) +{ + GdkFontPrivate *private; + XCharStruct *chars; + gint width; + guint ch = character & 0xff; /* get rid of sign-extension */ + XFontStruct *xfont; + XFontSet fontset; + + g_return_val_if_fail (font != NULL, -1); + + private = (GdkFontPrivate*) font; + + switch (font->type) + { + case GDK_FONT_FONT: + /* only 8 bits characters are considered here */ + xfont = (XFontStruct *) private->xfont; + if ((xfont->min_byte1 == 0) && + (xfont->max_byte1 == 0) && + (ch >= xfont->min_char_or_byte2) && + (ch <= xfont->max_char_or_byte2)) + { + chars = xfont->per_char; + if (chars) + width = chars[ch - xfont->min_char_or_byte2].width; + else + width = xfont->min_bounds.width; + } + else + { + width = XTextWidth (xfont, &character, 1); + } + break; + case GDK_FONT_FONTSET: + fontset = (XFontSet) private->xfont; + width = XmbTextEscapement (fontset, &character, 1) ; + break; + default: + width = 0; + } + return width; +} + +gint +gdk_string_measure (GdkFont *font, + const gchar *string) +{ + g_return_val_if_fail (font != NULL, -1); + g_return_val_if_fail (string != NULL, -1); + + return gdk_text_measure (font, string, strlen (string)); +} + +gint +gdk_text_measure (GdkFont *font, + const gchar *text, + gint text_length) +{ + GdkFontPrivate *private; + XCharStruct overall; + XFontStruct *xfont; + XFontSet fontset; + XRectangle ink, log; + int direction; + int font_ascent; + int font_descent; + gint width; + + g_return_val_if_fail (font != NULL, -1); + g_return_val_if_fail (text != NULL, -1); + + private = (GdkFontPrivate*) font; + + switch (font->type) + { + case GDK_FONT_FONT: + xfont = (XFontStruct *) private->xfont; + if ((xfont->min_byte1 == 0) && (xfont->max_byte1 == 0)) + { + XTextExtents (xfont, text, text_length, + &direction, &font_ascent, &font_descent, + &overall); + } + else + { + XTextExtents16 (xfont, (XChar2b *) text, text_length / 2, + &direction, &font_ascent, &font_descent, + &overall); + } + width = overall.rbearing; + break; + case GDK_FONT_FONTSET: + fontset = (XFontSet) private->xfont; + XmbTextExtents (fontset, text, text_length, &ink, &log); + width = log.width; + break; + default: + width = 0; + } + return width; +} + +gint +gdk_char_measure (GdkFont *font, + gchar character) +{ + g_return_val_if_fail (font != NULL, -1); + + return gdk_text_measure (font, &character, 1); +} diff --git a/gdk/x11/gdkglobals-x11.c b/gdk/x11/gdkglobals-x11.c new file mode 100644 index 000000000..58f7bf844 --- /dev/null +++ b/gdk/x11/gdkglobals-x11.c @@ -0,0 +1,47 @@ +/* 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 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include <stdio.h> +#include <X11/Xlib.h> +#include "gdktypes.h" +#include "gdkprivate.h" + +gint gdk_debug_level = 0; +gint gdk_show_events = FALSE; +gint gdk_use_xshm = TRUE; +gchar *gdk_display_name = NULL; +Display *gdk_display = NULL; +gint gdk_screen; +Window gdk_root_window; +Window gdk_leader_window; +GdkWindowPrivate gdk_root_parent; +Atom gdk_wm_delete_window; +Atom gdk_wm_take_focus; +Atom gdk_wm_protocols; +Atom gdk_wm_window_protocols[2]; +Atom gdk_selection_property; +GdkDndGlobals gdk_dnd = {None,None,None, + None,None,None, + None, + None,None, + NULL, + 0, 0, + {0,0}}; +gchar *gdk_progname = NULL; +gchar *gdk_progclass = NULL; +gint gdk_error_code; +gint gdk_error_warnings = TRUE; diff --git a/gdk/x11/gdkimage-x11.c b/gdk/x11/gdkimage-x11.c new file mode 100644 index 000000000..bcda3119f --- /dev/null +++ b/gdk/x11/gdkimage-x11.c @@ -0,0 +1,492 @@ +/* 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 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include "../config.h" + +#include <sys/types.h> + +#if defined (HAVE_IPC_H) && defined (HAVE_SHM_H) && defined (HAVE_XSHM_H) +#define USE_SHM +#endif + +#ifdef USE_SHM +#include <sys/ipc.h> +#include <sys/shm.h> +#endif /* USE_SHM */ + +#include <X11/Xlib.h> +#include <X11/Xutil.h> + +#ifdef USE_SHM +#include <X11/extensions/XShm.h> +#endif /* USE_SHM */ + +#include "gdk.h" +#include "gdkprivate.h" + + +static void gdk_image_put_normal (GdkDrawable *drawable, + GdkGC *gc, + GdkImage *image, + gint xsrc, + gint ysrc, + gint xdest, + gint ydest, + gint width, + gint height); +static void gdk_image_put_shared (GdkDrawable *drawable, + GdkGC *gc, + GdkImage *image, + gint xsrc, + gint ysrc, + gint xdest, + gint ydest, + gint width, + gint height); + + +static GList *image_list = NULL; + + +void +gdk_image_exit () +{ + GdkImage *image; + + while (image_list) + { + image = image_list->data; + gdk_image_destroy (image); + } +} + +GdkImage * +gdk_image_new_bitmap(GdkVisual *visual, gpointer data, gint w, gint h) +/* + * Desc: create a new bitmap image + */ +{ + Visual *xvisual; + GdkImage *image; + GdkImagePrivate *private; + private = g_new(GdkImagePrivate, 1); + image = (GdkImage *) private; + private->xdisplay = gdk_display; + private->image_put = gdk_image_put_normal; + image->type = GDK_IMAGE_NORMAL; + image->visual = visual; + image->width = w; + image->height = h; + image->depth = 1; + xvisual = ((GdkVisualPrivate*) visual)->xvisual; + private->ximage = XCreateImage(private->xdisplay, xvisual, 1, XYBitmap, + 0, 0, w ,h, 8, 0); + private->ximage->data = data; + private->ximage->bitmap_bit_order = MSBFirst; + private->ximage->byte_order = MSBFirst; + image->byte_order = MSBFirst; + image->mem = private->ximage->data; + image->bpl = private->ximage->bytes_per_line; + image->bpp = 1; + return(image); +} /* gdk_image_new_bitmap() */ + +static int +gdk_image_check_xshm(Display *display) +/* + * Desc: query the server for support for the MIT_SHM extension + * Return: 0 = not available + * 1 = shared XImage support available + * 2 = shared Pixmap support available also + */ +{ +#ifdef USE_SHM + int major, minor, ignore; + Bool pixmaps; + + if (XQueryExtension(display, "MIT-SHM", &ignore, &ignore, &ignore)) + { + if (XShmQueryVersion(display, &major, &minor, &pixmaps )==True) + { + return (pixmaps==True) ? 2 : 1; + } + } +#endif /* USE_SHM */ + return 0; +} + +void +gdk_image_init () +{ + if (gdk_use_xshm) + { + if (!gdk_image_check_xshm (gdk_display)) + { + g_warning ("MIT-SHM Extension not availible on server"); + gdk_use_xshm = False; + } + } +} + +GdkImage* +gdk_image_new (GdkImageType type, + GdkVisual *visual, + gint width, + gint height) +{ + GdkImage *image; + GdkImagePrivate *private; +#ifdef USE_SHM + XShmSegmentInfo *x_shm_info; +#endif /* USE_SHM */ + Visual *xvisual; + + switch (type) + { + case GDK_IMAGE_FASTEST: + image = gdk_image_new (GDK_IMAGE_SHARED, visual, width, height); + + if (!image) + image = gdk_image_new (GDK_IMAGE_NORMAL, visual, width, height); + break; + + default: + private = g_new (GdkImagePrivate, 1); + image = (GdkImage*) private; + + private->xdisplay = gdk_display; + private->image_put = NULL; + + image->type = type; + image->visual = visual; + image->width = width; + image->height = height; + image->depth = visual->depth; + + xvisual = ((GdkVisualPrivate*) visual)->xvisual; + + switch (type) + { + case GDK_IMAGE_SHARED: +#ifdef USE_SHM + if (gdk_use_xshm) + { + private->image_put = gdk_image_put_shared; + + private->x_shm_info = g_new (XShmSegmentInfo, 1); + x_shm_info = private->x_shm_info; + + private->ximage = XShmCreateImage (private->xdisplay, xvisual, visual->depth, + ZPixmap, NULL, x_shm_info, width, height); + if (private->ximage == NULL) + { + g_warning ("XShmCreateImage failed"); + + g_free (image); + gdk_use_xshm = False; + return NULL; + } + + x_shm_info->shmid = shmget (IPC_PRIVATE, + private->ximage->bytes_per_line * private->ximage->height, + IPC_CREAT | 0777); + + if (x_shm_info->shmid == -1) + { + g_warning ("shmget failed!"); + + XDestroyImage (private->ximage); + g_free (private->x_shm_info); + g_free (image); + + gdk_use_xshm = False; + gdk_use_xshm = False; + return NULL; + } + + x_shm_info->readOnly = False; + x_shm_info->shmaddr = shmat (x_shm_info->shmid, 0, 0); + private->ximage->data = x_shm_info->shmaddr; + + if (x_shm_info->shmaddr == (char*) -1) + { + g_warning ("shmat failed!"); + + XDestroyImage (private->ximage); + shmctl (x_shm_info->shmid, IPC_RMID, 0); + + g_free (private->x_shm_info); + g_free (image); + + return NULL; + } + +#ifdef IPC_RMID_DEFERRED_RELEASE + if (x_shm_info->shmaddr != (char*) -1) + shmctl (x_shm_info->shmid, IPC_RMID, 0); +#endif + + gdk_error_code = 0; + gdk_error_warnings = 0; + + XShmAttach (private->xdisplay, x_shm_info); + XSync (private->xdisplay, False); + + gdk_error_warnings = 1; + if (gdk_error_code == -1) + { + g_warning ("XShmAttach failed!"); + + XDestroyImage (private->ximage); + shmdt (x_shm_info->shmaddr); + shmctl (x_shm_info->shmid, IPC_RMID, 0); + + g_free (private->x_shm_info); + g_free (image); + + gdk_use_xshm = False; + return NULL; + } + + if (image) + image_list = g_list_prepend (image_list, image); + } + else + { + g_free (image); + return NULL; + } + break; +#else /* USE_SHM */ + g_free (image); + return NULL; +#endif /* USE_SHM */ + case GDK_IMAGE_NORMAL: + private->image_put = gdk_image_put_normal; + + private->ximage = XCreateImage (private->xdisplay, xvisual, visual->depth, + ZPixmap, 0, 0, width, height, 32, 0); + + private->ximage->data = g_new (char, private->ximage->bytes_per_line * + private->ximage->height); + break; + + case GDK_IMAGE_FASTEST: + g_assert_not_reached (); + } + + if (image) + { + image->byte_order = private->ximage->byte_order; + image->mem = private->ximage->data; + image->bpl = private->ximage->bytes_per_line; + + switch (private->ximage->bits_per_pixel) + { + case 8: + image->bpp = 1; + break; + case 16: + image->bpp = 2; + break; + case 24: + image->bpp = 3; + break; + case 32: + image->bpp = 4; + break; + } + } + } + + return image; +} + +GdkImage* +gdk_image_get (GdkWindow *window, + gint x, + gint y, + gint width, + gint height) +{ + GdkImage *image; + GdkImagePrivate *private; + GdkWindowPrivate *win_private; + + g_return_val_if_fail (window != NULL, NULL); + + win_private = (GdkWindowPrivate *) window; + + private = g_new (GdkImagePrivate, 1); + image = (GdkImage*) private; + + private->xdisplay = gdk_display; + private->image_put = gdk_image_put_normal; + private->ximage = XGetImage (private->xdisplay, + win_private->xwindow, + x, y, width, height, + AllPlanes, ZPixmap); + + image->type = GDK_IMAGE_NORMAL; + image->visual = gdk_window_get_visual (window); + image->width = width; + image->height = height; + image->depth = private->ximage->depth; + + image->mem = private->ximage->data; + image->bpl = private->ximage->bytes_per_line; + image->bpp = 1; + + return image; +} + +guint32 +gdk_image_get_pixel (GdkImage *image, + gint x, + gint y) +{ + guint32 pixel; + GdkImagePrivate *private; + + g_return_val_if_fail (image != NULL, 0); + + private = (GdkImagePrivate *) image; + + pixel = XGetPixel (private->ximage, x, y); + + return pixel; +} + +void +gdk_image_put_pixel (GdkImage *image, + gint x, + gint y, + guint32 pixel) +{ + GdkImagePrivate *private; + + g_return_if_fail (image != NULL); + + private = (GdkImagePrivate *) image; + + pixel = XPutPixel (private->ximage, x, y, pixel); +} + +void +gdk_image_destroy (GdkImage *image) +{ + GdkImagePrivate *private; +#ifdef USE_SHM + XShmSegmentInfo *x_shm_info; +#endif /* USE_SHM */ + + g_return_if_fail (image != NULL); + + private = (GdkImagePrivate*) image; + switch (image->type) + { + case GDK_IMAGE_NORMAL: + XDestroyImage (private->ximage); + break; + + case GDK_IMAGE_SHARED: +#ifdef USE_SHM + XShmDetach (private->xdisplay, private->x_shm_info); + XDestroyImage (private->ximage); + + x_shm_info = private->x_shm_info; + shmdt (x_shm_info->shmaddr); + shmctl (x_shm_info->shmid, IPC_RMID, 0); + + g_free (private->x_shm_info); + + image_list = g_list_remove (image_list, image); +#else /* USE_SHM */ + g_error ("trying to destroy shared memory image when gdk was compiled without shared memory support"); +#endif /* USE_SHM */ + break; + + case GDK_IMAGE_FASTEST: + g_assert_not_reached (); + } + + g_free (image); +} + +static void +gdk_image_put_normal (GdkDrawable *drawable, + GdkGC *gc, + GdkImage *image, + gint xsrc, + gint ysrc, + gint xdest, + gint ydest, + gint width, + gint height) +{ + GdkWindowPrivate *drawable_private; + GdkImagePrivate *image_private; + GdkGCPrivate *gc_private; + + g_return_if_fail (drawable != NULL); + g_return_if_fail (image != NULL); + g_return_if_fail (gc != NULL); + + drawable_private = (GdkWindowPrivate*) drawable; + image_private = (GdkImagePrivate*) image; + gc_private = (GdkGCPrivate*) gc; + + g_return_if_fail (image->type == GDK_IMAGE_NORMAL); + + XPutImage (drawable_private->xdisplay, drawable_private->xwindow, + gc_private->xgc, image_private->ximage, + xsrc, ysrc, xdest, ydest, width, height); +} + +static void +gdk_image_put_shared (GdkDrawable *drawable, + GdkGC *gc, + GdkImage *image, + gint xsrc, + gint ysrc, + gint xdest, + gint ydest, + gint width, + gint height) +{ +#ifdef USE_SHM + GdkWindowPrivate *drawable_private; + GdkImagePrivate *image_private; + GdkGCPrivate *gc_private; + + g_return_if_fail (drawable != NULL); + g_return_if_fail (image != NULL); + g_return_if_fail (gc != NULL); + + drawable_private = (GdkWindowPrivate*) drawable; + image_private = (GdkImagePrivate*) image; + gc_private = (GdkGCPrivate*) gc; + + g_return_if_fail (image->type == GDK_IMAGE_SHARED); + + XShmPutImage (drawable_private->xdisplay, drawable_private->xwindow, + gc_private->xgc, image_private->ximage, + xsrc, ysrc, xdest, ydest, width, height, False); +#else /* USE_SHM */ + g_error ("trying to draw shared memory image when gdk was compiled without shared memory support"); +#endif /* USE_SHM */ +} diff --git a/gdk/x11/gdkinput-gxi.c b/gdk/x11/gdkinput-gxi.c new file mode 100644 index 000000000..a30e05f95 --- /dev/null +++ b/gdk/x11/gdkinput-gxi.c @@ -0,0 +1,628 @@ +/* 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 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifdef XINPUT_GXI + +/* #define DEBUG_SWITCHING */ + +#include <gxid_lib.h> + +/* Forward declarations */ +static void gdk_input_gxi_select_notify (GdkDevicePrivate *gdkdev); +static gint gdk_input_gxi_set_mode (guint32 deviceid, GdkInputMode mode); +static gint gdk_input_is_extension_device (guint32 deviceid); +static void gdk_input_gxi_configure_event (XConfigureEvent *xevent, + GdkWindow *window); +static void gdk_input_gxi_enter_event (XCrossingEvent *xevent, + GdkWindow *window); +static gint gdk_input_gxi_other_event (GdkEvent *event, + XEvent *xevent, + GdkWindow *window); +static void gdk_input_gxi_update_device (GdkDevicePrivate *gdkdev); + +static gint gdk_input_gxi_window_none_event (GdkEvent *event, XEvent *xevent); +static gint gdk_input_gxi_enable_window (GdkWindow *window, + GdkDevicePrivate *gdkdev); +static gint gdk_input_gxi_disable_window (GdkWindow *window, + GdkDevicePrivate *gdkdev); +static Window gdk_input_find_root_child(Display *dpy, Window w); +static void gdk_input_compute_obscuring(GdkInputWindow *input_window); +static gint gdk_input_is_obscured(GdkInputWindow *input_window, gdouble x, + gdouble y); +static GdkTimeCoord *gdk_input_gxi_motion_events (GdkWindow *window, + guint32 deviceid, + guint32 start, + guint32 stop, + gint *nevents_return); +static void gdk_input_gxi_get_pointer (GdkWindow *window, + guint32 deviceid, + gdouble *x, + gdouble *y, + gdouble *pressure, + gdouble *xtilt, + gdouble *ytilt, + GdkModifierType *mask); +static gint gdk_input_gxi_grab_pointer (GdkWindow * window, + gint owner_events, + GdkEventMask event_mask, + GdkWindow * confine_to, + guint32 time); +static void gdk_input_gxi_ungrab_pointer (guint32 time); + +/* Local variables */ + +static GdkDevicePrivate *gdk_input_current_device; +static GdkDevicePrivate *gdk_input_core_pointer; + +void +gdk_input_init(void) +{ + GList *tmp_list; + + gdk_input_vtable.set_mode = gdk_input_gxi_set_mode; + gdk_input_vtable.set_axes = gdk_input_common_set_axes; + gdk_input_vtable.motion_events = gdk_input_gxi_motion_events; + gdk_input_vtable.get_pointer = gdk_input_gxi_get_pointer; + gdk_input_vtable.grab_pointer = gdk_input_gxi_grab_pointer; + gdk_input_vtable.ungrab_pointer = gdk_input_gxi_ungrab_pointer; + gdk_input_vtable.configure_event = gdk_input_gxi_configure_event; + gdk_input_vtable.enter_event = gdk_input_gxi_enter_event; + gdk_input_vtable.other_event = gdk_input_gxi_other_event; + gdk_input_vtable.window_none_event = gdk_input_gxi_window_none_event; + gdk_input_vtable.enable_window = gdk_input_gxi_enable_window; + gdk_input_vtable.disable_window = gdk_input_gxi_disable_window; + + gdk_input_ignore_core = FALSE; + gdk_input_core_pointer = NULL; + + if (!gdk_input_gxid_host) + { + gdk_input_gxid_host = getenv("GXID_HOST"); + } + if (!gdk_input_gxid_port) + { + char *t = getenv("GXID_PORT"); + if (t) + gdk_input_gxid_port = atoi(t); + } + + gdk_input_common_init(TRUE); + + /* find initial core pointer */ + + for (tmp_list = gdk_input_devices; tmp_list; tmp_list = tmp_list->next) + { + GdkDevicePrivate *gdkdev = (GdkDevicePrivate *)tmp_list->data; + if (gdk_input_is_extension_device(gdkdev->info.deviceid)) + { + gdk_input_gxi_select_notify (gdkdev); + } + else + { + if (gdkdev->info.deviceid != GDK_CORE_POINTER) + gdk_input_core_pointer = gdkdev; + } + } +} + +static void +gdk_input_gxi_select_notify (GdkDevicePrivate *gdkdev) +{ + XEventClass class; + + ChangeDeviceNotify (gdkdev->xdevice, gdkdev->changenotify_type, class); + + XSelectExtensionEvent (gdk_display, gdk_root_window, &class, 1); +} + +/* Set the core pointer. Device should already be enabled. */ +static gint +gdk_input_gxi_set_core_pointer(GdkDevicePrivate *gdkdev) +{ + int x_axis,y_axis; + + g_return_val_if_fail(gdkdev->xdevice,FALSE); + + x_axis = gdkdev->axis_for_use[GDK_AXIS_X]; + y_axis = gdkdev->axis_for_use[GDK_AXIS_Y]; + + g_return_val_if_fail(x_axis != -1 && y_axis != -1,FALSE); + + /* core_pointer might not be up to date so we check with the server + before change the pointer */ + + if ( !gdk_input_is_extension_device(gdkdev->info.deviceid) ) + { +#if 0 + if (gdkdev != gdk_input_core_pointer) + g_warning("core pointer inconsistency"); +#endif + return TRUE; + } + + if ( XChangePointerDevice(gdk_display,gdkdev->xdevice, x_axis, y_axis) + != Success ) + { + return FALSE; + } + else + { + gdk_input_gxi_update_device (gdk_input_core_pointer); + gdk_input_core_pointer = gdkdev; + return TRUE; + } +} + + +/* FIXME, merge with gdk_input_xfree_set_mode */ + +static gint +gdk_input_gxi_set_mode (guint32 deviceid, GdkInputMode mode) +{ + GList *tmp_list; + GdkDevicePrivate *gdkdev; + GdkInputMode old_mode; + GdkInputWindow *input_window; + + gdkdev = gdk_input_find_device(deviceid); + g_return_val_if_fail (gdkdev != NULL,FALSE); + old_mode = gdkdev->info.mode; + + if (gdkdev->info.mode == mode) + return TRUE; + + gdkdev->info.mode = mode; + + if (old_mode != GDK_MODE_DISABLED) + { + for (tmp_list = gdk_input_windows; tmp_list; tmp_list = tmp_list->next) + { + input_window = (GdkInputWindow *)tmp_list->data; + if (input_window->mode != GDK_EXTENSION_EVENTS_CURSOR) + gdk_input_disable_window (input_window->window, gdkdev); + } + } + + if (mode != GDK_MODE_DISABLED) + { + for (tmp_list = gdk_input_windows; tmp_list; tmp_list = tmp_list->next) + { + input_window = (GdkInputWindow *)tmp_list->data; + if (input_window->mode != GDK_EXTENSION_EVENTS_CURSOR) + if (!gdk_input_enable_window(input_window->window, gdkdev)) + { + gdk_input_set_mode(deviceid, old_mode); + return FALSE; + } + } + } + + return TRUE; + +} + +gint +gdk_input_is_extension_device (guint32 deviceid) +{ + XDeviceInfo *devices; + int num_devices, loop; + + if (deviceid == GDK_CORE_POINTER) + return FALSE; + + devices = XListInputDevices(gdk_display, &num_devices); + for(loop=0; loop<num_devices; loop++) + { + if ((devices[loop].id == deviceid) && (devices[loop].use == IsXExtensionDevice)) + { + XFreeDeviceList(devices); + return TRUE; + } + } + + XFreeDeviceList(devices); + return FALSE; +} + +static void +gdk_input_gxi_configure_event (XConfigureEvent *xevent, GdkWindow *window) +{ + GdkInputWindow *input_window; + gint root_x, root_y; + + input_window = gdk_input_window_find(window); + g_return_if_fail (input_window != NULL); + + gdk_input_get_root_relative_geometry(gdk_display,GDK_WINDOW_XWINDOW(window), + &root_x, &root_y, NULL, NULL); + input_window->root_x = root_x; + input_window->root_y = root_y; + gdk_input_compute_obscuring(input_window); +} + +static void +gdk_input_gxi_enter_event (XCrossingEvent *xevent, GdkWindow *window) +{ + GdkInputWindow *input_window; + + input_window = gdk_input_window_find(window); + g_return_if_fail (input_window != NULL); + + gdk_input_compute_obscuring(input_window); +} + +static gint +gdk_input_gxi_other_event (GdkEvent *event, + XEvent *xevent, + GdkWindow *window) +{ + GdkInputWindow *input_window; + + GdkDevicePrivate *gdkdev; + gint return_val; + + input_window = gdk_input_window_find(window); + g_return_val_if_fail (window != NULL, -1); + + /* This is a sort of a hack, as there isn't any XDeviceAnyEvent - + but it's potentially faster than scanning through the types of + every device. If we were deceived, then it won't match any of + the types for the device anyways */ + gdkdev = gdk_input_find_device(((XDeviceButtonEvent *)xevent)->deviceid); + + if (!gdkdev) { + return -1; /* we don't handle it - not an XInput event */ + } + + if (gdkdev->info.mode == GDK_MODE_DISABLED || + input_window->mode == GDK_EXTENSION_EVENTS_CURSOR) + return FALSE; + + if (gdkdev != gdk_input_current_device && + xevent->type != gdkdev->changenotify_type) + { + gdk_input_current_device = gdkdev; + } + + return_val = gdk_input_common_other_event (event, xevent, + input_window, gdkdev); + + if (return_val > 0 && event->type == GDK_MOTION_NOTIFY && + (!gdkdev->button_state) && (!input_window->grabbed) && + ((event->motion.x < 0) || (event->motion.y < 0) || + (event->motion.x > ((GdkWindowPrivate *)window)->width) || + (event->motion.y > ((GdkWindowPrivate *)window)->height) || + gdk_input_is_obscured(input_window,event->motion.x,event->motion.y))) + { +#ifdef DEBUG_SWITCHING + g_print("gdkinput: Setting core pointer to %d on motion at (%f,%f)\n", + gdkdev->info.deviceid,event->motion.x,event->motion.y); + g_print(" window geometry is: %dx%d\n", + ((GdkWindowPrivate *)window)->width, + ((GdkWindowPrivate *)window)->height); +#endif + gdk_input_gxi_set_core_pointer(gdkdev); + return FALSE; + } + else + return return_val; + +} + +static void +gdk_input_gxi_update_device (GdkDevicePrivate *gdkdev) +{ + GList *t; + + if (gdk_input_is_extension_device (gdkdev->info.deviceid)) + { + if (!gdkdev->xdevice) + { + gdkdev->xdevice = XOpenDevice(gdk_display, gdkdev->info.deviceid); + gdk_input_gxi_select_notify (gdkdev); + gdkdev->needs_update = 1; + } + if (gdkdev->needs_update && gdkdev->xdevice) + { + for (t = gdk_input_windows; t; t = t->next) + gdk_input_common_select_events (((GdkInputWindow *)t->data)->window, + gdkdev); + gdkdev->needs_update = 0; + } + } +} + +static gint +gdk_input_gxi_window_none_event (GdkEvent *event, XEvent *xevent) +{ + GdkDevicePrivate *gdkdev = + gdk_input_find_device(((XDeviceButtonEvent *)xevent)->deviceid); + + if (!gdkdev) { + return -1; /* we don't handle it - not an XInput event */ + } + + if (xevent->type == gdkdev->changenotify_type) + { + if (gdk_input_core_pointer != gdkdev) + { +#ifdef DEBUG_SWITCHING + g_print("ChangeNotify from %d to %d:\n", + gdk_input_core_pointer->info.deviceid, + gdkdev->info.deviceid); +#endif + gdk_input_gxi_update_device (gdk_input_core_pointer); + gdk_input_core_pointer = gdkdev; + } + } + + return FALSE; +} + +static gint +gdk_input_gxi_enable_window (GdkWindow *window, GdkDevicePrivate *gdkdev) +{ + GdkInputWindow *input_window; + + input_window = gdk_input_window_find (window); + g_return_val_if_fail (input_window != NULL, FALSE); + + if (!gdkdev->claimed) + { + if (gxid_claim_device(gdk_input_gxid_host, gdk_input_gxid_port, + gdkdev->info.deviceid, + GDK_WINDOW_XWINDOW(window), FALSE) != + GXID_RETURN_OK) + { + g_warning("Could not get device (is gxid running?)\n"); + return FALSE; + } + gdkdev->claimed = TRUE; + } + + if (gdkdev->xdevice && gdkdev != gdk_input_core_pointer) + gdk_input_common_select_events(window, gdkdev); + else + gdkdev->needs_update = TRUE; + + return TRUE; +} + +static gint +gdk_input_gxi_disable_window(GdkWindow *window, GdkDevicePrivate *gdkdev) +{ + GdkInputWindow *input_window; + + input_window = gdk_input_window_find (window); + g_return_val_if_fail (input_window != NULL, FALSE); + + if (gdkdev->claimed) + { + gxid_release_device(gdk_input_gxid_host, gdk_input_gxid_port, + gdkdev->info.deviceid, + GDK_WINDOW_XWINDOW(window)); + + gdkdev->claimed = FALSE; + } + + if (gdkdev->xdevice && gdkdev != gdk_input_core_pointer) + gdk_input_common_select_events(window, gdkdev); + else + gdkdev->needs_update = TRUE; + + return TRUE; +} + +static gint +gdk_input_is_obscured(GdkInputWindow *input_window, gdouble x, gdouble y) +{ + int i; + for (i=0;i<input_window->num_obscuring;i++) + { + GdkRectangle *rect = &input_window->obscuring[i]; + if ((x >= rect->x) && + (y >= rect->y) && + (x < rect->x + rect->width) && + (y < rect->y + rect->height)) + return TRUE; + } + return FALSE; +} + +/* If this routine needs fixing, the corresponding routine + in gxid.c will need it too. */ + +static Window +gdk_input_find_root_child(Display *dpy, Window w) +{ + Window root,parent; + Window *children; + int nchildren; + + parent = w; + do + { + w = parent; + XQueryTree(dpy,w,&root,&parent,&children,&nchildren); + if (children) XFree(children); + } + while (parent != root); + + return w; +} + +void +gdk_input_compute_obscuring(GdkInputWindow *input_window) +{ + int i; + int x,y,width,height; + int xc,yc,widthc,heightc,border_widthc,depthc; + + Window root,parent; + Window *children; + int nchildren; + + Window w = GDK_WINDOW_XWINDOW(input_window->window); + Window root_child = gdk_input_find_root_child(gdk_display,w); + gdk_input_get_root_relative_geometry(gdk_display,w,&x,&y,&width,&height); + + input_window->root_x = x; + input_window->root_y = y; + + XQueryTree(gdk_display,GDK_ROOT_WINDOW(), + &root,&parent,&children,&nchildren); + + + if (input_window->obscuring) + g_free(input_window->obscuring); + input_window->obscuring = 0; + input_window->num_obscuring = 0; + + for (i=0;i<nchildren;i++) + if (children[i] == root_child) + break; + + if (i>=nchildren-1) + { + if (nchildren) + XFree(children); + return; + } + + input_window->obscuring = g_new(GdkRectangle,(nchildren-i-1)); + + for (i=i+1;i<nchildren;i++) + { + int xmin, xmax, ymin, ymax; + XGetGeometry(gdk_display,children[i],&root,&xc,&yc,&widthc,&heightc, + &border_widthc, &depthc); + xmin = xc>x ? xc : x; + xmax = (xc+widthc)<(x+width) ? xc+widthc : x+width; + ymin = yc>y ? yc : y; + ymax = (yc+heightc)<(y+height) ? yc+heightc : y+height; + if ((xmin < xmax) && (ymin < ymax)) + { + XWindowAttributes attributes; + XGetWindowAttributes(gdk_display,children[i],&attributes); + if (attributes.map_state == IsViewable) + { + GdkRectangle *rect = &input_window->obscuring[input_window->num_obscuring]; + + /* we store the whole window, not just the obscuring part */ + rect->x = xc - x; + rect->y = yc - y; + rect->width = widthc; + rect->height = heightc; + input_window->num_obscuring++; + } + } + } + + if (nchildren) + XFree(children); +} + +static void +gdk_input_gxi_get_pointer (GdkWindow *window, + guint32 deviceid, + gdouble *x, + gdouble *y, + gdouble *pressure, + gdouble *xtilt, + gdouble *ytilt, + GdkModifierType *mask) +{ + GdkDevicePrivate *gdkdev; + + gdkdev = gdk_input_find_device (deviceid); + g_return_if_fail (gdkdev != NULL); + + if (gdkdev == gdk_input_core_pointer) + gdk_input_common_get_pointer (window, GDK_CORE_POINTER, x, y, + pressure, xtilt, ytilt, mask); + else + gdk_input_common_get_pointer (window, deviceid, x, y, + pressure, xtilt, ytilt, mask); +} + +static GdkTimeCoord * +gdk_input_gxi_motion_events (GdkWindow *window, + guint32 deviceid, + guint32 start, + guint32 stop, + gint *nevents_return) +{ + GdkDevicePrivate *gdkdev; + + gdkdev = gdk_input_find_device (deviceid); + g_return_val_if_fail (gdkdev != NULL, NULL); + + + if (gdkdev == gdk_input_core_pointer) + return gdk_input_motion_events (window, GDK_CORE_POINTER, start, stop, + nevents_return); + else + return gdk_input_common_motion_events (window, deviceid, start, stop, + nevents_return); + +} + +static gint +gdk_input_gxi_grab_pointer (GdkWindow * window, + gint owner_events, + GdkEventMask event_mask, + GdkWindow * confine_to, + guint32 time) +{ + GdkInputWindow *input_window, *new_window; + GList *tmp_list; + + tmp_list = gdk_input_windows; + while (tmp_list) + { + input_window = (GdkInputWindow *)tmp_list->data; + if (input_window->grabbed) + return AlreadyGrabbed; + + if (input_window->window == window) + new_window = input_window; + + tmp_list = tmp_list->next; + } + + new_window->grabbed = TRUE; + return Success; +} + +static void +gdk_input_gxi_ungrab_pointer (guint32 time) +{ + GdkInputWindow *input_window; + GList *tmp_list; + + tmp_list = gdk_input_windows; + while (tmp_list) + { + input_window = (GdkInputWindow *)tmp_list->data; + if (input_window->grabbed) + input_window->grabbed = FALSE; + tmp_list = tmp_list->next; + } +} + +#endif /* XINPUT_GXI */ diff --git a/gdk/x11/gdkinput-none.c b/gdk/x11/gdkinput-none.c new file mode 100644 index 000000000..8ae8c4189 --- /dev/null +++ b/gdk/x11/gdkinput-none.c @@ -0,0 +1,72 @@ +/* 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 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifdef XINPUT_NONE + +static void gdk_input_none_get_pointer (GdkWindow *window, + guint32 deviceid, + gdouble *x, + gdouble *y, + gdouble *pressure, + gdouble *xtilt, + gdouble *ytilt, + GdkModifierType *mask); + +void +gdk_input_init () +{ + gdk_input_vtable.set_mode = NULL; + gdk_input_vtable.set_axes = NULL; + gdk_input_vtable.motion_events = NULL; + gdk_input_vtable.get_pointer = gdk_input_none_get_pointer; + gdk_input_vtable.grab_pointer = NULL; + gdk_input_vtable.ungrab_pointer = NULL; + gdk_input_vtable.configure_event = NULL; + gdk_input_vtable.enter_event = NULL; + gdk_input_vtable.other_event = NULL; + gdk_input_vtable.window_none_event = NULL; + gdk_input_vtable.enable_window = NULL; + gdk_input_vtable.disable_window = NULL; + + gdk_input_devices = g_list_append (NULL, &gdk_input_core_info); + + gdk_input_ignore_core = FALSE; +} + +static void +gdk_input_none_get_pointer (GdkWindow *window, + guint32 deviceid, + gdouble *x, + gdouble *y, + gdouble *pressure, + gdouble *xtilt, + gdouble *ytilt, + GdkModifierType *mask) +{ + gint x_int, y_int; + + gdk_window_get_pointer (window, &x_int, &y_int, mask); + + if (x) *x = x_int; + if (y) *y = y_int; + if (pressure) *pressure = 0.5; + if (xtilt) *xtilt = 0; + if (ytilt) *ytilt = 0; +} + +#endif /* XINPUT_NONE */ diff --git a/gdk/x11/gdkinput-x11.c b/gdk/x11/gdkinput-x11.c new file mode 100644 index 000000000..5e457e0aa --- /dev/null +++ b/gdk/x11/gdkinput-x11.c @@ -0,0 +1,687 @@ +/* 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 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#if defined(XINPUT_GXI) || defined(XINPUT_XFREE) + +/* Forward declarations */ +static void gdk_input_get_root_relative_geometry (Display *dpy, Window w, + int *x_ret, int *y_ret, + int *width_ret, + int *height_ret); +static GdkDevicePrivate *gdk_input_device_new(XDeviceInfo *device, + gint include_core); +static void gdk_input_common_find_events(GdkWindow *window, + GdkDevicePrivate *gdkdev, + gint mask, + XEventClass *classes, + int *num_classes); +static void gdk_input_common_select_events(GdkWindow *window, + GdkDevicePrivate *gdkdev); +static void gdk_input_translate_coordinates(GdkDevicePrivate *gdkdev, + GdkInputWindow *input_window, + gint *axis_data, + gdouble *x, gdouble *y, + gdouble *pressure, + gdouble *xtilt, gdouble *ytilt); +static guint gdk_input_translate_state(guint state, guint device_state); +static gint gdk_input_common_init(gint include_core); +static gint gdk_input_common_other_event (GdkEvent *event, + XEvent *xevent, + GdkInputWindow *input_window, + GdkDevicePrivate *gdkdev); +static void gdk_input_common_set_axes (guint32 deviceid, GdkAxisUse *axes); +static GdkTimeCoord * gdk_input_common_motion_events (GdkWindow *window, + guint32 deviceid, + guint32 start, + guint32 stop, + gint *nevents_return); +static void gdk_input_common_get_pointer (GdkWindow *window, + guint32 deviceid, + gdouble *x, + gdouble *y, + gdouble *pressure, + gdouble *xtilt, + gdouble *ytilt, + GdkModifierType *mask); + +/* Global variables */ + +static gint gdk_input_root_width; +static gint gdk_input_root_height; + +static void +gdk_input_get_root_relative_geometry(Display *dpy, Window w, int *x_ret, int *y_ret, + int *width_ret, int *height_ret) +{ + Window root,parent; + Window *children; + int nchildren; + int x,y,width,height; + int xc,yc,widthc,heightc,border_widthc,depthc; + + XQueryTree(dpy,w,&root,&parent,&children,&nchildren); + if (children) XFree(children); + XGetGeometry(dpy,w,&root,&x,&y,&width,&height,&border_widthc, + &depthc); + x += border_widthc; + y += border_widthc; + + while (root != parent) + { + w = parent; + XQueryTree(dpy,w,&root,&parent,&children,&nchildren); + if (children) XFree(children); + XGetGeometry(dpy,w,&root,&xc,&yc,&widthc,&heightc, + &border_widthc,&depthc); + x += xc + border_widthc; + y += yc + border_widthc; + } + + if (x_ret) + *x_ret = x; + if (y_ret) + *y_ret = y; + if (width_ret) + *width_ret = width; + if (height_ret) + *height_ret = height; +} + +static GdkDevicePrivate * +gdk_input_device_new(XDeviceInfo *device, gint include_core) +{ + GdkDevicePrivate *gdkdev; + gchar *tmp_name, *p; + XAnyClassPtr class; + gint i,j; + + gdkdev = g_new(GdkDevicePrivate,1); + + gdkdev->info.deviceid = device->id; + if (device->name[0]) { + gdkdev->info.name = g_new(char, strlen(device->name)+1); + strcpy(gdkdev->info.name,device->name); + } else { + /* XFree86 3.2 gives an empty name to the default core devices, + (fixed in 3.2A) */ + gdkdev->info.name = g_strdup("pointer"); + strcpy(gdkdev->info.name,"pointer"); + gdkdev->info.source = GDK_SOURCE_MOUSE; + } + + gdkdev->info.mode = GDK_MODE_DISABLED; + + /* Try to figure out what kind of device this is by its name - + could invite a very, very, long list... Lowercase name + for comparison purposes */ + + tmp_name = g_strdup(gdkdev->info.name); + for (p = tmp_name; *p; p++) + { + if (*p >= 'A' && *p <= 'Z') + *p += 'a' - 'A'; + } + + if (!strcmp (tmp_name, "pointer")) + gdkdev->info.source = GDK_SOURCE_MOUSE; + else if (!strcmp (tmp_name, "wacom") || + !strcmp (tmp_name, "pen")) + gdkdev->info.source = GDK_SOURCE_PEN; + else if (!strcmp (tmp_name, "eraser")) + gdkdev->info.source = GDK_SOURCE_ERASER; + else if (!strcmp (tmp_name, "cursor")) + gdkdev->info.source = GDK_SOURCE_CURSOR; + else + gdkdev->info.source = GDK_SOURCE_PEN; + + g_free(tmp_name); + + gdkdev->xdevice = NULL; + + /* step through the classes */ + + gdkdev->info.num_axes = 0; + gdkdev->axes = 0; + gdkdev->info.has_cursor = 0; + gdkdev->needs_update = FALSE; + gdkdev->claimed = FALSE; + gdkdev->button_state = 0; + + class = device->inputclassinfo; + for (i=0;i<device->num_classes;i++) + { + switch (class->class) { + case ButtonClass: + { + break; + } + case ValuatorClass: + { + XValuatorInfo *xvi = (XValuatorInfo *)class; + gdkdev->info.num_axes = xvi->num_axes; + gdkdev->axes = g_new(GdkAxisInfo, xvi->num_axes); + gdkdev->info.axes = g_new(GdkAxisUse, xvi->num_axes); + for (j=0;j<xvi->num_axes;j++) + { + gdkdev->axes[j].resolution = + gdkdev->axes[j].xresolution = xvi->axes[j].resolution; + gdkdev->axes[j].min_value = + gdkdev->axes[j].xmin_value = xvi->axes[j].min_value; + gdkdev->axes[j].max_value = + gdkdev->axes[j].xmax_value = xvi->axes[j].max_value; + gdkdev->info.axes[j] = GDK_AXIS_IGNORE; + } + j=0; + if (j<xvi->num_axes) + gdkdev->info.axes[j++] = GDK_AXIS_X; + if (j<xvi->num_axes) + gdkdev->info.axes[j++] = GDK_AXIS_Y; + if (j<xvi->num_axes) + gdkdev->info.axes[j++] = GDK_AXIS_PRESSURE; + if (j<xvi->num_axes) + gdkdev->info.axes[j++] = GDK_AXIS_XTILT; + if (j<xvi->num_axes) + gdkdev->info.axes[j++] = GDK_AXIS_YTILT; + + /* set up reverse lookup on axis use */ + for (j=GDK_AXIS_IGNORE;j<GDK_AXIS_LAST;j++) + gdkdev->axis_for_use[j] = -1; + + for (j=0;j<xvi->num_axes;j++) + if (gdkdev->info.axes[j] != GDK_AXIS_IGNORE) + gdkdev->axis_for_use[gdkdev->info.axes[j]] = j; + + break; + } + } + class = (XAnyClassPtr)(((char *)class) + class->length); + } + /* return NULL if no axes */ + if (!gdkdev->info.num_axes || !gdkdev->axes || + (!include_core && device->use == IsXPointer)) + { + g_free(gdkdev->info.name); + if (gdkdev->axes) + g_free(gdkdev->axes); + g_free(gdkdev); + return NULL; + } + + if (device->use != IsXPointer) + gdkdev->xdevice = XOpenDevice(gdk_display, gdkdev->info.deviceid); + + return gdkdev; +} + +static void +gdk_input_common_find_events(GdkWindow *window, + GdkDevicePrivate *gdkdev, + gint mask, + XEventClass *classes, + int *num_classes) +{ + gint i; + XEventClass class; + + i = 0; + /* We have to track press and release events in pairs to keep + track of button state correctly and implement grabbing */ + if (mask & GDK_BUTTON_PRESS_MASK || mask & GDK_BUTTON_RELEASE_MASK) + { + DeviceButtonPress (gdkdev->xdevice, gdkdev->buttonpress_type, + class); + if (class != 0) + classes[i++] = class; + DeviceButtonRelease (gdkdev->xdevice, gdkdev->buttonrelease_type, + class); + if (class != 0) + classes[i++] = class; + } + if (mask & GDK_POINTER_MOTION_MASK) + { + DeviceMotionNotify (gdkdev->xdevice, gdkdev->motionnotify_type, class); + if (class != 0) + classes[i++] = class; + } + if (mask & GDK_POINTER_MOTION_HINT_MASK) + { + /* We'll get into trouble if the macros change, but at least we'll + know about it, and we avoid warnings now */ + DevicePointerMotionHint (gdkdev->xdevice, 0, class); + if (class != 0) + classes[i++] = class; + } + if (mask & GDK_PROXIMITY_IN_MASK) + { + ProximityIn (gdkdev->xdevice, gdkdev->proximityin_type, class); + if (class != 0) + classes[i++] = class; + } + if (mask & GDK_PROXIMITY_OUT_MASK) + { + ProximityOut (gdkdev->xdevice, gdkdev->proximityout_type, class); + if (class != 0) + classes[i++] = class; + } + + *num_classes = i; +} + +static void +gdk_input_common_select_events(GdkWindow *window, + GdkDevicePrivate *gdkdev) +{ + XEventClass classes[6]; + gint num_classes; + + if (gdkdev->info.mode == GDK_MODE_DISABLED) + gdk_input_common_find_events(window, gdkdev, 0, classes, &num_classes); + else + gdk_input_common_find_events(window, gdkdev, + ((GdkWindowPrivate *)window)->extension_events, + classes, &num_classes); + + XSelectExtensionEvent (gdk_display, + GDK_WINDOW_XWINDOW(window), + classes, num_classes); +} + +gint +gdk_input_common_init(gint include_core) +{ + char **extensions; + XDeviceInfo *devices; + int num_devices; + int num_extensions, loop; + Display *display = gdk_display; + + /* Init global vars */ + gdk_window_get_geometry(NULL, /* use root window */ + NULL,NULL, + &gdk_input_root_width,&gdk_input_root_height, + NULL); + + /* Init XInput extension */ + + extensions = XListExtensions(display, &num_extensions); + for (loop = 0; loop < num_extensions && + (strcmp(extensions[loop], "XInputExtension") != 0); loop++); + XFreeExtensionList(extensions); + if (loop == num_extensions) /* XInput extension not found */ + return FALSE; + + gdk_input_devices = 0; + devices = XListInputDevices(display, &num_devices); + + for(loop=0; loop<num_devices; loop++) + { + GdkDevicePrivate *gdkdev = gdk_input_device_new(&devices[loop], + include_core); + if (gdkdev) + gdk_input_devices = g_list_append(gdk_input_devices, gdkdev); + } + XFreeDeviceList(devices); + + gdk_input_devices = g_list_append (gdk_input_devices, &gdk_input_core_info); + + return TRUE; +} + +static void +gdk_input_translate_coordinates (GdkDevicePrivate *gdkdev, + GdkInputWindow *input_window, + gint *axis_data, + gdouble *x, gdouble *y, gdouble *pressure, + gdouble *xtilt, gdouble *ytilt) +{ + GdkWindowPrivate *win_priv; + + int x_axis, y_axis, pressure_axis, xtilt_axis, ytilt_axis; + + double device_width, device_height; + double x_offset, y_offset, x_scale, y_scale; + + win_priv = (GdkWindowPrivate *) input_window->window; + + x_axis = gdkdev->axis_for_use[GDK_AXIS_X]; + y_axis = gdkdev->axis_for_use[GDK_AXIS_Y]; + pressure_axis = gdkdev->axis_for_use[GDK_AXIS_PRESSURE]; + xtilt_axis = gdkdev->axis_for_use[GDK_AXIS_XTILT]; + ytilt_axis = gdkdev->axis_for_use[GDK_AXIS_YTILT]; + + device_width = gdkdev->axes[x_axis].max_value - + gdkdev->axes[x_axis].min_value; + device_height = gdkdev->axes[y_axis].max_value - + gdkdev->axes[y_axis].min_value; + + if (gdkdev->info.mode == GDK_MODE_SCREEN) + { + x_scale = gdk_input_root_width / device_width; + y_scale = gdk_input_root_height / device_height; + + x_offset = - input_window->root_x; + y_offset = - input_window->root_y; + } + else /* GDK_MODE_WINDOW */ + { + double device_aspect = (device_height*gdkdev->axes[y_axis].resolution) / + (device_width*gdkdev->axes[x_axis].resolution); + + if (device_aspect * win_priv->width >= win_priv->height) + { + /* device taller than window */ + x_scale = win_priv->width / device_width; + y_scale = (x_scale * gdkdev->axes[x_axis].resolution) + / gdkdev->axes[y_axis].resolution; + + x_offset = 0; + y_offset = -(device_height * y_scale - + win_priv->height)/2; + } + else + { + /* window taller than device */ + y_scale = win_priv->height / device_height; + x_scale = (y_scale * gdkdev->axes[y_axis].resolution) + / gdkdev->axes[x_axis].resolution; + + y_offset = 0; + x_offset = - (device_width * x_scale - win_priv->width)/2; + } + } + + if (x) *x = x_offset + x_scale*axis_data[x_axis]; + if (y) *y = y_offset + y_scale*axis_data[y_axis]; + + if (pressure) + { + if (pressure_axis != -1) + *pressure = ((double)axis_data[pressure_axis] + - gdkdev->axes[pressure_axis].min_value) + / (gdkdev->axes[pressure_axis].max_value + - gdkdev->axes[pressure_axis].min_value); + else + *pressure = 0.5; + } + + if (xtilt) + { + if (xtilt_axis != -1) + { + *xtilt = 2. * (double)(axis_data[xtilt_axis] - + (gdkdev->axes[xtilt_axis].min_value + + gdkdev->axes[xtilt_axis].max_value)/2) / + (gdkdev->axes[xtilt_axis].max_value - + gdkdev->axes[xtilt_axis].min_value); + } + else *xtilt = 0; + } + + if (ytilt) + { + if (ytilt_axis != -1) + { + *ytilt = 2. * (double)(axis_data[ytilt_axis] - + (gdkdev->axes[ytilt_axis].min_value + + gdkdev->axes[ytilt_axis].max_value)/2) / + (gdkdev->axes[ytilt_axis].max_value - + gdkdev->axes[ytilt_axis].min_value); + } + else + *ytilt = 0; + } +} + +/* combine the state of the core device and the device state + into one - for now we do this in a simple-minded manner - + we just take the keyboard portion of the core device and + the button portion (all of?) the device state. + Any button remapping should go on here. */ +static guint +gdk_input_translate_state(guint state, guint device_state) +{ + return device_state | (state & 0xFF); +} + +static gint +gdk_input_common_other_event (GdkEvent *event, + XEvent *xevent, + GdkInputWindow *input_window, + GdkDevicePrivate *gdkdev) +{ + if ((xevent->type == gdkdev->buttonpress_type) || + (xevent->type == gdkdev->buttonrelease_type)) + { + XDeviceButtonEvent *xdbe = (XDeviceButtonEvent *)(xevent); + + if (xdbe->type == gdkdev->buttonpress_type) + { + event->button.type = GDK_BUTTON_PRESS; + gdkdev->button_state |= 1 << xdbe->button; + } + else + { + event->button.type = GDK_BUTTON_RELEASE; + gdkdev->button_state &= ~(1 << xdbe->button); + } + event->button.window = input_window->window; + event->button.time = xdbe->time; + event->button.source = gdkdev->info.source; + event->button.deviceid = xdbe->deviceid; + + gdk_input_translate_coordinates (gdkdev,input_window, xdbe->axis_data, + &event->button.x,&event->button.y, + &event->button.pressure, + &event->button.xtilt, + &event->button.ytilt); + event->button.state = gdk_input_translate_state(xdbe->state,xdbe->device_state); + event->button.button = xdbe->button; + + return TRUE; + } + + if (xevent->type == gdkdev->motionnotify_type) + { + XDeviceMotionEvent *xdme = (XDeviceMotionEvent *)(xevent); + + gdk_input_translate_coordinates(gdkdev,input_window,xdme->axis_data, + &event->motion.x,&event->motion.y, + &event->motion.pressure, + &event->motion.xtilt, + &event->motion.ytilt); + + event->motion.type = GDK_MOTION_NOTIFY; + event->motion.window = input_window->window; + event->motion.time = xdme->time; + event->motion.deviceid = xdme->deviceid; + event->motion.state = gdk_input_translate_state(xdme->state, + xdme->device_state); + event->motion.source = gdkdev->info.source; + event->motion.deviceid = xdme->deviceid; + + if (gdk_show_events) + g_print ("motion notify:\t\twindow: %ld device: %ld x,y: %f %f hint: %s\n", + xdme->window, + xdme->deviceid, + event->motion.x, event->motion.y, + (xevent->xmotion.is_hint) ? "true" : "false"); + + + return TRUE; + } + + if (xevent->type == gdkdev->proximityin_type || + xevent->type == gdkdev->proximityout_type) + { + XProximityNotifyEvent *xpne = (XProximityNotifyEvent *)(xevent); + + event->proximity.type = (xevent->type == gdkdev->proximityin_type)? + GDK_PROXIMITY_IN:GDK_PROXIMITY_OUT; + event->proximity.window = input_window->window; + event->proximity.time = xpne->time; + event->proximity.source = gdkdev->info.source; + event->proximity.deviceid = xpne->deviceid; + + return TRUE; + } + + return -1; /* wasn't one of our event types */ +} + +static void +gdk_input_common_set_axes (guint32 deviceid, GdkAxisUse *axes) +{ + int i; + GdkDevicePrivate *gdkdev = gdk_input_find_device(deviceid); + g_return_if_fail (gdkdev != NULL); + + for (i=GDK_AXIS_IGNORE;i<GDK_AXIS_LAST;i++) + { + gdkdev->axis_for_use[i] = -1; + } + + for (i=0;i<gdkdev->info.num_axes;i++) + { + gdkdev->info.axes[i] = axes[i]; + gdkdev->axis_for_use[axes[i]] = i; + } +} + +static GdkTimeCoord * +gdk_input_common_motion_events (GdkWindow *window, + guint32 deviceid, + guint32 start, + guint32 stop, + gint *nevents_return) +{ + GdkTimeCoord *coords; + XDeviceTimeCoord *device_coords; + GdkInputWindow *input_window; + GdkDevicePrivate *gdkdev; + + int mode_return; + int axis_count_return; + int i; + + gdkdev = gdk_input_find_device (deviceid); + input_window = gdk_input_window_find (window); + + g_return_val_if_fail (gdkdev != NULL, NULL); + g_return_val_if_fail (gdkdev->xdevice != NULL, NULL); + g_return_val_if_fail (input_window != NULL, NULL); + + device_coords = XGetDeviceMotionEvents (gdk_display, + gdkdev->xdevice, + start, stop, + nevents_return, &mode_return, + &axis_count_return); + + if (device_coords) + { + coords = g_new (GdkTimeCoord, *nevents_return); + + for (i=0; i<*nevents_return; i++) + { + gdk_input_translate_coordinates (gdkdev, input_window, + device_coords[i].data, + &coords[i].x, &coords[i].y, + &coords[i].pressure, + &coords[i].xtilt, &coords[i].ytilt); + } + XFreeDeviceMotionEvents (device_coords); + + return coords; + } + else + return NULL; +} + +static void +gdk_input_common_get_pointer (GdkWindow *window, + guint32 deviceid, + gdouble *x, + gdouble *y, + gdouble *pressure, + gdouble *xtilt, + gdouble *ytilt, + GdkModifierType *mask) +{ + GdkDevicePrivate *gdkdev; + GdkInputWindow *input_window; + XDeviceState *state; + XInputClass *input_class; + gint x_int, y_int; + gint i; + + /* we probably need to get the mask in any case */ + + if (deviceid == GDK_CORE_POINTER) + { + gdk_window_get_pointer (window, &x_int, &y_int, mask); + if (x) *x = x_int; + if (y) *y = y_int; + if (pressure) *pressure = 0.5; + if (xtilt) *xtilt = 0; + if (ytilt) *ytilt = 0; + } + else + { + if (mask) + gdk_window_get_pointer (window, NULL, NULL, mask); + + gdkdev = gdk_input_find_device (deviceid); + input_window = gdk_input_window_find (window); + + g_return_if_fail (gdkdev != NULL); + g_return_if_fail (gdkdev->xdevice != NULL); + g_return_if_fail (input_window != NULL); + + state = XQueryDeviceState (gdk_display, gdkdev->xdevice); + input_class = state->data; + for (i=0; i<state->num_classes; i++) + { + switch (input_class->class) + { + case ValuatorClass: + gdk_input_translate_coordinates(gdkdev, input_window, + ((XValuatorState *)input_class)->valuators, + x, y, pressure, + xtilt, ytilt); + + + break; + case ButtonClass: + if (mask) + { + *mask &= ~(GDK_BUTTON1_MASK | GDK_BUTTON2_MASK | + GDK_BUTTON3_MASK | GDK_BUTTON4_MASK | + GDK_BUTTON5_MASK); + for (i=0; i < ((XButtonState *)input_class)->num_buttons; i++) + { + if (((XButtonState *)input_class)->buttons[i]) + *mask |= GDK_BUTTON1_MASK << i; + } + } + break; + } + input_class = (XInputClass *)(((char *)input_class)+input_class->length); + } + } +} + +#endif diff --git a/gdk/x11/gdkinput-xfree.c b/gdk/x11/gdkinput-xfree.c new file mode 100644 index 000000000..f74249008 --- /dev/null +++ b/gdk/x11/gdkinput-xfree.c @@ -0,0 +1,368 @@ +/* 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 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifdef XINPUT_XFREE + +/* forward declarations */ + +static gint gdk_input_xfree_set_mode (guint32 deviceid, GdkInputMode mode); +static void gdk_input_check_proximity(); +static void gdk_input_xfree_configure_event (XConfigureEvent *xevent, + GdkWindow *window); +static void gdk_input_xfree_enter_event (XCrossingEvent *xevent, + GdkWindow *window); +static gint gdk_input_xfree_other_event (GdkEvent *event, + XEvent *xevent, + GdkWindow *window); +static gint gdk_input_xfree_enable_window(GdkWindow *window, + GdkDevicePrivate *gdkdev); +static gint gdk_input_xfree_disable_window(GdkWindow *window, + GdkDevicePrivate *gdkdev); +static gint gdk_input_xfree_grab_pointer (GdkWindow * window, + gint owner_events, + GdkEventMask event_mask, + GdkWindow * confine_to, + guint32 time); +static void gdk_input_xfree_ungrab_pointer (guint32 time); + +void +gdk_input_init(void) +{ + gdk_input_vtable.set_mode = gdk_input_xfree_set_mode; + gdk_input_vtable.set_axes = gdk_input_common_set_axes; + gdk_input_vtable.motion_events = gdk_input_common_motion_events; + gdk_input_vtable.get_pointer = gdk_input_common_get_pointer; + gdk_input_vtable.grab_pointer = gdk_input_xfree_grab_pointer; + gdk_input_vtable.ungrab_pointer = gdk_input_xfree_ungrab_pointer; + gdk_input_vtable.configure_event = gdk_input_xfree_configure_event; + gdk_input_vtable.enter_event = gdk_input_xfree_enter_event; + gdk_input_vtable.other_event = gdk_input_xfree_other_event; + gdk_input_vtable.window_none_event = NULL; + gdk_input_vtable.enable_window = gdk_input_xfree_enable_window; + gdk_input_vtable.disable_window = gdk_input_xfree_disable_window; + + gdk_input_ignore_core = FALSE; + gdk_input_common_init(FALSE); +} + +static gint +gdk_input_xfree_set_mode (guint32 deviceid, GdkInputMode mode) +{ + GList *tmp_list; + GdkDevicePrivate *gdkdev; + GdkInputMode old_mode; + GdkInputWindow *input_window; + + gdkdev = gdk_input_find_device(deviceid); + g_return_val_if_fail (gdkdev != NULL,FALSE); + old_mode = gdkdev->info.mode; + + if (gdkdev->info.mode == mode) + return TRUE; + + gdkdev->info.mode = mode; + + if (mode == GDK_MODE_WINDOW) + { + gdkdev->info.has_cursor = FALSE; + for (tmp_list = gdk_input_windows; tmp_list; tmp_list = tmp_list->next) + { + input_window = (GdkInputWindow *)tmp_list->data; + if (input_window->mode != GDK_EXTENSION_EVENTS_CURSOR) + gdk_input_enable_window (input_window->window, gdkdev); + else + if (old_mode != GDK_MODE_DISABLED) + gdk_input_disable_window (input_window->window, gdkdev); + } + } + else if (mode == GDK_MODE_SCREEN) + { + gdkdev->info.has_cursor = TRUE; + for (tmp_list = gdk_input_windows; tmp_list; tmp_list = tmp_list->next) + gdk_input_enable_window (((GdkInputWindow *)tmp_list->data)->window, + gdkdev); + } + else /* mode == GDK_MODE_DISABLED */ + { + for (tmp_list = gdk_input_windows; tmp_list; tmp_list = tmp_list->next) + { + input_window = (GdkInputWindow *)tmp_list->data; + if (old_mode != GDK_MODE_WINDOW || + input_window->mode != GDK_EXTENSION_EVENTS_CURSOR) + gdk_input_disable_window (input_window->window, gdkdev); + } + } + + return TRUE; + +} + +static void +gdk_input_check_proximity() +{ + gint new_proximity = 0; + GList *tmp_list = gdk_input_devices; + + while (tmp_list && !new_proximity) + { + GdkDevicePrivate *gdkdev = (GdkDevicePrivate *)(tmp_list->data); + + if (gdkdev->info.mode != GDK_MODE_DISABLED + && gdkdev->info.deviceid != GDK_CORE_POINTER + && gdkdev->xdevice) + { + XDeviceState *state = XQueryDeviceState(GDK_DISPLAY(), + gdkdev->xdevice); + XInputClass *xic; + int i; + + xic = state->data; + for (i=0; i<state->num_classes; i++) + { + if (xic->class == ValuatorClass) + { + XValuatorState *xvs = (XValuatorState *)xic; + if ((xvs->mode & ProximityState) == InProximity) + { + new_proximity = TRUE; + } + break; + } + xic = (XInputClass *)((char *)xic + xic->length); + } + } + tmp_list = tmp_list->next; + } + + gdk_input_ignore_core = new_proximity; +} + +static void +gdk_input_xfree_configure_event (XConfigureEvent *xevent, GdkWindow *window) +{ + GdkInputWindow *input_window; + gint root_x, root_y; + + input_window = gdk_input_window_find(window); + g_return_if_fail (window != NULL); + + gdk_input_get_root_relative_geometry(GDK_DISPLAY(),GDK_WINDOW_XWINDOW(window), + &root_x, + &root_y, NULL, NULL); + + input_window->root_x = root_x; + input_window->root_y = root_y; +} + +static void +gdk_input_xfree_enter_event (XCrossingEvent *xevent, + GdkWindow *window) +{ + GdkInputWindow *input_window; + gint root_x, root_y; + + input_window = gdk_input_window_find(window); + g_return_if_fail (window != NULL); + + gdk_input_check_proximity(); + + gdk_input_get_root_relative_geometry(GDK_DISPLAY(),GDK_WINDOW_XWINDOW(window), + &root_x, + &root_y, NULL, NULL); + + input_window->root_x = root_x; + input_window->root_y = root_y; +} + +static gint +gdk_input_xfree_other_event (GdkEvent *event, + XEvent *xevent, + GdkWindow *window) +{ + GdkInputWindow *input_window; + + GdkDevicePrivate *gdkdev; + gint return_val; + + input_window = gdk_input_window_find(window); + g_return_val_if_fail (window != NULL, -1); + + /* This is a sort of a hack, as there isn't any XDeviceAnyEvent - + but it's potentially faster than scanning through the types of + every device. If we were deceived, then it won't match any of + the types for the device anyways */ + gdkdev = gdk_input_find_device(((XDeviceButtonEvent *)xevent)->deviceid); + + if (!gdkdev) { + return -1; /* we don't handle it - not an XInput event */ + } + + /* FIXME: It would be nice if we could just get rid of the events + entirely, instead of having to ignore them */ + if (gdkdev->info.mode == GDK_MODE_DISABLED || + (gdkdev->info.mode == GDK_MODE_WINDOW + && input_window->mode == GDK_EXTENSION_EVENTS_CURSOR)) + return FALSE; + + if (!gdk_input_ignore_core) + gdk_input_check_proximity(); + + return_val = gdk_input_common_other_event (event, xevent, + input_window, gdkdev); + + if (return_val > 0 && event->type == GDK_PROXIMITY_OUT && + gdk_input_ignore_core) + gdk_input_check_proximity(); + + /* Do a passive button grab. We have to be careful not to release + an explicit grab, if any. Doubling the grab should be harmless, + but we check anyways. */ + + /* FIXME, finding the proper events here is going to be SLOW - but + we might have different sets for each window/device combination */ + + if (return_val> 0 && !input_window->grabbed) + { + if (event->type == GDK_BUTTON_PRESS) + { + XEventClass event_classes[6]; + gint num_classes; + + gdk_input_common_find_events (window, gdkdev, + ((GdkWindowPrivate *)window)->extension_events, + event_classes, &num_classes); + + XGrabDevice( GDK_DISPLAY(), gdkdev->xdevice, + GDK_WINDOW_XWINDOW (window), + TRUE, num_classes, event_classes, + GrabModeAsync, GrabModeAsync, event->button.time); + } + else if (event->type == GDK_BUTTON_RELEASE) + XUngrabDevice( GDK_DISPLAY(), gdkdev->xdevice, event->button.time); + } + + return return_val; +} + +static gint +gdk_input_xfree_enable_window(GdkWindow *window, GdkDevicePrivate *gdkdev) +{ + /* FIXME: watchout, gdkdev might be core pointer, never opened */ + gdk_input_common_select_events (window, gdkdev); + return TRUE; +} + +static gint +gdk_input_xfree_disable_window(GdkWindow *window, GdkDevicePrivate *gdkdev) +{ + gdk_input_common_select_events (window, gdkdev); + return TRUE; +} + +static gint +gdk_input_xfree_grab_pointer (GdkWindow * window, + gint owner_events, + GdkEventMask event_mask, + GdkWindow * confine_to, + guint32 time) +{ + GdkInputWindow *input_window, *new_window; + GdkDevicePrivate *gdkdev; + GList *tmp_list; + XEventClass event_classes[6]; + gint num_classes; + + tmp_list = gdk_input_windows; + new_window = NULL; + while (tmp_list) + { + input_window = (GdkInputWindow *)tmp_list->data; + if (input_window->grabbed) + return AlreadyGrabbed; + + if (input_window->window == window) + { + new_window = input_window; + break; + } + + tmp_list = tmp_list->next; + } + + g_return_if_fail (new_window == NULL); + + new_window->grabbed = TRUE; + + tmp_list = gdk_input_devices; + while (tmp_list) + { + gdkdev = (GdkDevicePrivate *)tmp_list->data; + if (gdkdev->info.deviceid != GDK_CORE_POINTER && + gdkdev->xdevice && !gdkdev->button_state) + { + gdk_input_common_find_events (window, gdkdev, + ((GdkWindowPrivate *)window)->extension_events, + event_classes, &num_classes); + + /* FIXME: we should do something on failure */ + XGrabDevice( GDK_DISPLAY(), gdkdev->xdevice, + GDK_WINDOW_XWINDOW (window), + TRUE, num_classes, event_classes, + GrabModeAsync, GrabModeAsync, time); + } + tmp_list = tmp_list->next; + } + + return Success; +} + +static void +gdk_input_xfree_ungrab_pointer (guint32 time) +{ + GdkInputWindow *input_window; + GdkDevicePrivate *gdkdev; + GList *tmp_list; + + tmp_list = gdk_input_windows; + while (tmp_list) + { + input_window = (GdkInputWindow *)tmp_list->data; + if (input_window->grabbed) + break; + tmp_list = tmp_list->next; + } + + if (tmp_list) /* we found a grabbed window */ + { + input_window->grabbed = FALSE; + + tmp_list = gdk_input_devices; + while (tmp_list) + { + gdkdev = (GdkDevicePrivate *)tmp_list->data; + if (gdkdev->info.deviceid != GDK_CORE_POINTER && + gdkdev->xdevice && !gdkdev->button_state) + { + XUngrabDevice( gdk_display, gdkdev->xdevice, time); + } + tmp_list = tmp_list->next; + } + } +} + +#endif /* XINPUT_XFREE */ diff --git a/gdk/x11/gdkinput.c b/gdk/x11/gdkinput.c new file mode 100644 index 000000000..ad4b1fcc9 --- /dev/null +++ b/gdk/x11/gdkinput.c @@ -0,0 +1,324 @@ +/* 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 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include <stdlib.h> +#include <X11/Xlib.h> +#include <X11/Xutil.h> +#include "../config.h" +#include "gdk.h" +#include "gdkx.h" +#include "gdkprivate.h" +#include "gdkinput.h" + + +/* Forward declarations */ + +static gint gdk_input_enable_window (GdkWindow *window, + GdkDevicePrivate *gdkdev); +static gint gdk_input_disable_window (GdkWindow *window, + GdkDevicePrivate *gdkdev); +static GdkInputWindow *gdk_input_window_find (GdkWindow *window); +static GdkDevicePrivate *gdk_input_find_device (guint32 id); + + +/* Incorporate the specific routines depending on compilation options */ + +static GdkAxisUse gdk_input_core_axes[] = { GDK_AXIS_X, GDK_AXIS_Y }; + +static GdkDeviceInfo gdk_input_core_info = +{ + GDK_CORE_POINTER, + "Core Pointer", + GDK_SOURCE_MOUSE, + GDK_MODE_SCREEN, + TRUE, + 2, + gdk_input_core_axes +}; + +/* Global variables */ + +GdkInputVTable gdk_input_vtable; +/* information about network port and host for gxid daemon */ +gchar *gdk_input_gxid_host; +gint gdk_input_gxid_port; +gint gdk_input_ignore_core; + +/* Local variables */ + +static GList *gdk_input_devices; +static GList *gdk_input_windows; + +#include "gdkinputnone.h" +#include "gdkinputcommon.h" +#include "gdkinputxfree.h" +#include "gdkinputgxi.h" + +GList * +gdk_input_list_devices () +{ + return gdk_input_devices; +} + +void +gdk_input_set_source (guint32 deviceid, GdkInputSource source) +{ + GdkDevicePrivate *gdkdev = gdk_input_find_device(deviceid); + g_return_if_fail (gdkdev != NULL); + + gdkdev->info.source = source; +} + +gint +gdk_input_set_mode (guint32 deviceid, GdkInputMode mode) +{ + if (deviceid == GDK_CORE_POINTER) + return FALSE; + + if (gdk_input_vtable.set_mode) + return gdk_input_vtable.set_mode(deviceid,mode); + else + return FALSE; +} + +void +gdk_input_set_axes (guint32 deviceid, GdkAxisUse *axes) +{ + if (deviceid != GDK_CORE_POINTER && gdk_input_vtable.set_axes) + gdk_input_vtable.set_axes (deviceid, axes); +} + +GdkTimeCoord * +gdk_input_motion_events (GdkWindow *window, + guint32 deviceid, + guint32 start, + guint32 stop, + gint *nevents_return) +{ + XTimeCoord *xcoords; + GdkTimeCoord *coords; + int i; + + if (deviceid == GDK_CORE_POINTER) + { + xcoords = XGetMotionEvents (gdk_display, + ((GdkWindowPrivate *)window)->xwindow, + start, stop, nevents_return); + if (xcoords) + { + coords = g_new (GdkTimeCoord, *nevents_return); + for (i=0; i<*nevents_return; i++) + { + coords[i].time = xcoords[i].time; + coords[i].x = xcoords[i].x; + coords[i].y = xcoords[i].y; + coords[i].pressure = 0.5; + coords[i].xtilt = 0.0; + coords[i].ytilt = 0.0; + } + + XFree(xcoords); + + return coords; + } + else + return NULL; + } + else + { + if (gdk_input_vtable.motion_events) + { + return gdk_input_vtable.motion_events(window, + deviceid, start, stop, + nevents_return); + } + else + { + *nevents_return = 0; + return NULL; + } + } +} + +static gint +gdk_input_enable_window (GdkWindow *window, GdkDevicePrivate *gdkdev) +{ + if (gdk_input_vtable.enable_window) + return gdk_input_vtable.enable_window (window, gdkdev); + else + return TRUE; +} + +static gint +gdk_input_disable_window (GdkWindow *window, GdkDevicePrivate *gdkdev) +{ + if (gdk_input_vtable.disable_window) + return gdk_input_vtable.disable_window(window,gdkdev); + else + return TRUE; +} + + +static GdkInputWindow * +gdk_input_window_find(GdkWindow *window) +{ + GList *tmp_list; + + for (tmp_list=gdk_input_windows; tmp_list; tmp_list=tmp_list->next) + if (((GdkInputWindow *)(tmp_list->data))->window == window) + return (GdkInputWindow *)(tmp_list->data); + + return NULL; /* Not found */ +} + +/* FIXME: this routine currently needs to be called between creation + and the corresponding configure event (because it doesn't get the + root_relative_geometry). This should work with + gtk_window_set_extension_events, but will likely fail in other + cases */ + +void +gdk_input_set_extension_events (GdkWindow *window, gint mask, + GdkExtensionMode mode) +{ + GList *tmp_list; + GdkInputWindow *iw; + + g_return_if_fail (window != NULL); + + if (mode == GDK_EXTENSION_EVENTS_NONE) + mask = 0; + + if (mask != 0) + { + iw = g_new(GdkInputWindow,1); + + iw->window = window; + iw->mode = mode; + + iw->obscuring = NULL; + iw->num_obscuring = 0; + iw->grabbed = FALSE; + + gdk_input_windows = g_list_append(gdk_input_windows,iw); + ((GdkWindowPrivate *)window)->extension_events = mask; + + /* Add enter window events to the event mask */ + /* FIXME, this is not needed for XINPUT_NONE */ + gdk_window_set_events (window, + gdk_window_get_events (window) | + GDK_ENTER_NOTIFY_MASK); + } + else + { + iw = gdk_input_window_find (window); + if (iw) + { + gdk_input_windows = g_list_remove(gdk_input_windows,iw); + g_free(iw); + } + + ((GdkWindowPrivate *)window)->extension_events = 0; + } + + for (tmp_list = gdk_input_devices; tmp_list; tmp_list = tmp_list->next) + { + GdkDevicePrivate *gdkdev = (GdkDevicePrivate *)(tmp_list->data); + + if (gdkdev->info.deviceid != GDK_CORE_POINTER) + { + if (mask != 0 && gdkdev->info.mode != GDK_MODE_DISABLED + && (gdkdev->info.has_cursor || mode == GDK_EXTENSION_EVENTS_ALL)) + gdk_input_enable_window(window,gdkdev); + else + gdk_input_disable_window(window,gdkdev); + } + } +} + +void +gdk_input_window_destroy (GdkWindow *window) +{ + GdkInputWindow *input_window; + + input_window = gdk_input_window_find (window); + g_return_if_fail (input_window != NULL); + + gdk_input_windows = g_list_remove(gdk_input_windows,input_window); + g_free(input_window); +} + +void +gdk_input_exit (void) +{ + GList *tmp_list; + GdkDevicePrivate *gdkdev; + + for (tmp_list = gdk_input_devices; tmp_list; tmp_list = tmp_list->next) + { + gdkdev = (GdkDevicePrivate *)(tmp_list->data); + if (gdkdev->info.deviceid != GDK_CORE_POINTER) + { + gdk_input_set_mode(gdkdev->info.deviceid,GDK_MODE_DISABLED); + + g_free(gdkdev->info.name); +#ifndef XINPUT_NONE + g_free(gdkdev->axes); +#endif + g_free(gdkdev->info.axes); + g_free(gdkdev); + } + } + + g_list_free(gdk_input_devices); + + for (tmp_list = gdk_input_windows; tmp_list; tmp_list = tmp_list->next) + { + g_free(tmp_list->data); + } + g_list_free(gdk_input_windows); +} + +static GdkDevicePrivate * +gdk_input_find_device(guint32 id) +{ + GList *tmp_list = gdk_input_devices; + GdkDevicePrivate *gdkdev; + while (tmp_list) + { + gdkdev = (GdkDevicePrivate *)(tmp_list->data); + if (gdkdev->info.deviceid == id) + return gdkdev; + tmp_list = tmp_list->next; + } + return NULL; +} + +void +gdk_input_window_get_pointer (GdkWindow *window, + guint32 deviceid, + gdouble *x, + gdouble *y, + gdouble *pressure, + gdouble *xtilt, + gdouble *ytilt, + GdkModifierType *mask) +{ + if (gdk_input_vtable.get_pointer) + gdk_input_vtable.get_pointer (window, deviceid, x, y, pressure, + xtilt, ytilt, mask); +} diff --git a/gdk/x11/gdkmain-x11.c b/gdk/x11/gdkmain-x11.c new file mode 100644 index 000000000..d5f85dd1e --- /dev/null +++ b/gdk/x11/gdkmain-x11.c @@ -0,0 +1,2897 @@ +/* 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 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include "../config.h" + +#include <ctype.h> +#include <locale.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <limits.h> + +#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> +#include <X11/cursorfont.h> +#include "gdk.h" +#include "gdkprivate.h" +#include "gdkinput.h" + + +#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 + typedef long fd_mask; +# 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; +}; + +struct _GdkPredicate +{ + GdkEventFunc func; + gpointer data; +}; + +/* + * Private function declarations + */ +static gint gdk_event_wait (void); +static gint gdk_event_translate (GdkEvent *event, + XEvent *xevent); +static Bool gdk_event_get_type (Display *display, + XEvent *xevent, + XPointer arg); +static void gdk_synthesize_click (GdkEvent *event, + gint nclicks); + +static void gdk_dnd_drag_begin (GdkWindow *initial_window); +static void gdk_dnd_drag_enter (Window dest); +static void gdk_dnd_drag_leave (Window dest); +static void gdk_dnd_drag_end (Window dest, + GdkPoint coords); +static GdkAtom gdk_dnd_check_types (GdkWindow *window, + XEvent *xevent); +static void gdk_print_atom (GdkAtom anatom); + +/* + * old junk from offix, we might use it though so leave it + */ +static Window gdk_drop_get_client_window (Display *dpy, + Window win); +static GdkWindow * gdk_drop_get_real_window (GdkWindow *w, + guint16 *x, + guint16 *y); +static void gdk_exit_func (void); +static int gdk_x_error (Display *display, + XErrorEvent *error); +static int gdk_x_io_error (Display *display); +static RETSIGTYPE gdk_signal (int signum); + + +/* Private variable declarations + */ +static int initialized = 0; /* 1 if the library is initialized, + * 0 otherwise. + */ +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. + */ + +static gint received_destroy_notify = FALSE; /* Did we just receive a destroy notify + * event? If so, we need to actually + * destroy the window which received + * it now. + */ +static GdkWindow *window_to_destroy = NULL; /* If we previously received a destroy + * notify event then this is the window + * which received that event. + */ + +static struct timeval start; /* The time at which the library was + * last initialized. + */ +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. + */ +static struct timeval *timerp; /* The actual timer passed to "select" + * This may be NULL, in which case + * "select" will block until an event + * arrives. + */ +static guint32 timer_val; /* The timeout length as specified by + * the user in milliseconds. + */ +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. + */ +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. + */ +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. + */ +static guint button_number[2]; /* The last 2 buttons to be pressed. + */ + +#define OTHER_XEVENT_BUFSIZE 4 +static XEvent other_xevent[OTHER_XEVENT_BUFSIZE]; /* XEvents passed along to user */ +static int other_xevent_i = 0; +static GList *putback_events = NULL; + +static gulong base_id; +static gint autorepeat; + + +/* + *-------------------------------------------------------------- + * 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 +gdk_init (int *argc, + char ***argv) +{ + XKeyboardState keyboard_state; + int synchronize; + int i, j, k; + XClassHint *class_hint; + int argc_orig = *argc; + char **argv_orig; + + argv_orig = 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; + + X_GETTIMEOFDAY (&start); + + 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); + + gdk_display_name = NULL; + + XSetErrorHandler (gdk_x_error); + XSetIOErrorHandler (gdk_x_io_error); + + synchronize = FALSE; + + if (argc && argv) + { + if (*argc > 0) + gdk_progname = (*argv)[0]; + + for (i = 1; i < *argc;) + { + if (strcmp ("--display", (*argv)[i]) == 0) + { + (*argv)[i] = NULL; + + if ((i + 1) < *argc) + { + 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 ("--show-events", (*argv)[i]) == 0) + { + (*argv)[i] = NULL; + gdk_show_events = TRUE; + } + else if (strcmp ("--no-show-events", (*argv)[i]) == 0) + { + (*argv)[i] = NULL; + gdk_show_events = FALSE; + } + else if (strcmp ("--no-xshm", (*argv)[i]) == 0) + { + (*argv)[i] = NULL; + gdk_use_xshm = FALSE; + } + else if (strcmp ("--debug-level", (*argv)[i]) == 0) + { + if ((i + 1) < *argc) + { + (*argv)[i++] = NULL; + gdk_debug_level = atoi ((*argv)[i]); + (*argv)[i] = NULL; + } + } + else if (strcmp ("-name", (*argv)[i]) == 0) + { + if ((i + 1) < *argc) + { + (*argv)[i++] = NULL; + gdk_progname = (*argv)[i]; + (*argv)[i] = NULL; + } + } + else if (strcmp ("-class", (*argv)[i]) == 0) + { + if ((i + 1) < *argc) + { + (*argv)[i++] = NULL; + gdk_progclass = (*argv)[i]; + (*argv)[i] = NULL; + } + } +#ifdef XINPUT_GXI + else if (strcmp ("--gxid_host", (*argv)[i]) == 0) + { + if ((i + 1) < *argc) + { + (*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++] = NULL; + gdk_input_gxid_port = atoi ((*argv)[i]); + (*argv)[i] = NULL; + } + } +#endif + i += 1; + } + + for (i = 1; i < *argc; i++) + { + for (k = i; k < *argc; k++) + if ((*argv)[k] != NULL) + break; + + if (k > i) + { + k -= i; + for (j = i + k; j < *argc; j++) + (*argv)[j-k] = (*argv)[j]; + *argc -= k; + } + } + } + else + { + gdk_progname = "<unknown>"; + } + + gdk_display = XOpenDisplay (gdk_display_name); + if (!gdk_display) + g_error ("cannot open display: %s", XDisplayName (gdk_display_name)); + + /* 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; + if (gdk_show_events) + g_print ("base id: %lu\n", base_id); + + connection_number = ConnectionNumber (gdk_display); + if (gdk_debug_level >= 1) + g_print ("connection number: %d\n", connection_number); + + if (synchronize) + XSynchronize (gdk_display, True); + + gdk_screen = DefaultScreen (gdk_display); + gdk_root_window = RootWindow (gdk_display, gdk_screen); + + gdk_leader_window = XCreateSimpleWindow(gdk_display, gdk_root_window, + 10, 10, 10, 10, 0, 0 , 0); + class_hint = XAllocClassHint(); + class_hint->res_name = gdk_progname; + 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); + + 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); + + gdk_dnd.gdk_XdeEnter = gdk_atom_intern("_XDE_ENTER", FALSE); + gdk_dnd.gdk_XdeLeave = gdk_atom_intern("_XDE_LEAVE", FALSE); + gdk_dnd.gdk_XdeRequest = gdk_atom_intern("_XDE_REQUEST", FALSE); + gdk_dnd.gdk_XdeDataAvailable = gdk_atom_intern("_XDE_DATA_AVAILABLE", FALSE); + gdk_dnd.gdk_XdeTypelist = gdk_atom_intern("_XDE_TYPELIST", FALSE); + gdk_dnd.gdk_cursor_dragdefault = XCreateFontCursor(gdk_display, XC_bogosity); + gdk_dnd.gdk_cursor_dragok = XCreateFontCursor(gdk_display, XC_heart); + + XGetKeyboardControl (gdk_display, &keyboard_state); + autorepeat = keyboard_state.global_auto_repeat; + + timer.tv_sec = 0; + timer.tv_usec = 0; + timerp = NULL; + + 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; + + if (ATEXIT (gdk_exit_func)) + g_warning ("unable to register exit function"); + + gdk_visual_init (); + gdk_window_init (); + gdk_image_init (); + gdk_input_init (); + + initialized = 1; +} + +/* + *-------------------------------------------------------------- + * 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) +{ + /* de-initialisation is done by the gdk_exit_funct(), + no need to do this here (Alex J.) */ + exit (errorcode); +} + +/* + *-------------------------------------------------------------- + * gdk_set_locale + * + * Arguments: + * + * Results: + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +gchar* +gdk_set_locale () +{ + if (!setlocale (LC_ALL,"")) + g_print ("locale not supported by C library\n"); + + if (!XSupportsLocale ()) + { + g_print ("locale not supported by Xlib, locale set to C\n"); + setlocale (LC_ALL, "C"); + } + + if (!XSetLocaleModifiers ("")) + { + g_print ("can not set locale modifiers\n"); + } + + 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 +gdk_events_pending () +{ + return XPending (gdk_display); +} + +/* + *-------------------------------------------------------------- + * gdk_event_get + * + * Gets the next event. + * + * Arguments: + * "event" is used to hold the received event. + * If "event" is NULL an event is received as normal + * however it is not placed in "event" (and thus no + * error occurs). + * + * Results: + * Returns TRUE if an event was received that we care about + * and FALSE otherwise. This function will also return + * before an event is received if the timeout interval + * runs out. + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +gint +gdk_event_get (GdkEvent *event, + GdkEventFunc pred, + gpointer data) +{ + GdkEvent *temp_event; + GdkPredicate event_pred; + GList *temp_list; + XEvent xevent; + + /* If the last event we received was a destroy notify + * event then we will actually destroy the "gdk" data + * structures now. We don't want to destroy them at the + * time of receiving the event since the main program + * may try to access them and may need to destroy user + * data that has been attached to the window + */ + if (received_destroy_notify) + { + if (gdk_show_events) + g_print ("destroying window:\twindow: %ld\n", + ((GdkWindowPrivate*) window_to_destroy)->xwindow - base_id); + + gdk_window_real_destroy (window_to_destroy); + received_destroy_notify = FALSE; + window_to_destroy = NULL; + } + + /* Initially we haven't received an event and want to + * return FALSE. If "event" is non-NULL, then initialize + * it to the nothing event. + */ + if (event) + { + event->any.type = GDK_NOTHING; + event->any.window = NULL; + event->any.send_event = FALSE; + } + + if (pred) + { + temp_list = putback_events; + while (temp_list) + { + temp_event = temp_list->data; + + 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; + } + + temp_list = temp_list->next; + } + + event_pred.func = pred; + event_pred.data = data; + + if (XCheckIfEvent (gdk_display, &xevent, gdk_event_get_type, (XPointer) &event_pred)) + if (event) + return gdk_event_translate (event, &xevent); + } + else + { + if (putback_events) + { + temp_event = putback_events->data; + *event = *temp_event; + + temp_list = putback_events; + putback_events = putback_events->next; + if (putback_events) + putback_events->prev = NULL; + + temp_list->next = NULL; + temp_list->prev = NULL; + g_list_free (temp_list); + g_free (temp_event); + + return TRUE; + } + + /* 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. + */ + XNextEvent (gdk_display, &xevent); + + event->any.send_event = xevent.xany.send_event; + + /* If "event" non-NULL. + */ + if (event) + return gdk_event_translate (event, &xevent); + } + } + + return FALSE; +} + +void +gdk_event_put (GdkEvent *event) +{ + GdkEvent *new_event; + + g_return_if_fail (event != NULL); + + new_event = g_new (GdkEvent, 1); + *new_event = *event; + + 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; + +GdkEvent* +gdk_event_copy (GdkEvent *event) +{ + GdkEvent *new_event; + + g_return_val_if_fail (event != NULL, NULL); + + if (event_chunk == NULL) + event_chunk = g_mem_chunk_new ("events", + sizeof (GdkEvent), + 4096, + G_ALLOC_AND_FREE); + + new_event = g_chunk_new (GdkEvent, event_chunk); + *new_event = *event; + gdk_window_ref (new_event->any.window); + 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); + + gdk_window_unref (event->any.window); + g_mem_chunk_free (event_chunk, event); +} + +/* + *-------------------------------------------------------------- + * gdk_set_debug_level + * + * Sets the debugging level. + * + * Arguments: + * "level" is the new debugging level. + * + * Results: + * + * Side effects: + * Other function calls to "gdk" use the debugging + * level to determine what kind of debugging information + * to print out. + * + *-------------------------------------------------------------- + */ + +void +gdk_set_debug_level (int level) +{ + gdk_debug_level = level; +} + +/* + *-------------------------------------------------------------- + * 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 +gdk_set_show_events (int show_events) +{ + gdk_show_events = show_events; +} + +void +gdk_set_use_xshm (gint use_xshm) +{ + gdk_use_xshm = use_xshm; +} + +gint +gdk_get_debug_level () +{ + return gdk_debug_level; +} + +gint +gdk_get_show_events () +{ + return gdk_show_events; +} + +gint +gdk_get_use_xshm () +{ + 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 +gdk_time_get () +{ + struct timeval end; + struct timeval elapsed; + guint32 milliseconds; + + X_GETTIMEOFDAY (&end); + + 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; + + milliseconds = (elapsed.tv_sec * 1000) + (elapsed.tv_usec / 1000); + + 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 +gdk_timer_get () +{ + 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; + +} + +void +gdk_timer_enable () +{ + timerp = &timer; +} + +void +gdk_timer_disable () +{ + timerp = NULL; +} + +gint +gdk_input_add (gint source, + GdkInputCondition condition, + GdkInputFunction function, + gpointer data) +{ + static gint next_tag = 1; + GList *list; + GdkInput *input; + gint tag; + + tag = 0; + list = inputs; + + while (list) + { + input = list->data; + list = list->next; + + if ((input->source == source) && (input->condition == condition)) + { + input->function = function; + input->data = data; + tag = input->tag; + } + } + + if (!tag) + { + input = g_new (GdkInput, 1); + input->tag = next_tag++; + input->source = source; + input->condition = condition; + input->function = function; + input->data = data; + tag = input->tag; + + inputs = g_list_prepend (inputs, input); + } + + return tag; +} + +void +gdk_input_remove (gint tag) +{ + GList *list; + GList *temp_list; + GdkInput *input; + + list = inputs; + while (list) + { + input = list->data; + + if (input->tag == tag) + { + temp_list = list; + + if (list->next) + list->next->prev = list->prev; + if (list->prev) + list->prev->next = list->next; + if (inputs == list) + inputs = list->next; + + temp_list->next = NULL; + temp_list->prev = NULL; + + g_free (temp_list->data); + g_list_free (temp_list); + break; + } + + list = list->next; + } +} + +/* + *-------------------------------------------------------------- + * gdk_pointer_grab + * + * Grabs the pointer to a specific window + * + * Arguments: + * "window" is the window which will receive the grab + * "owner_events" specifies whether events will be reported as is, + * or relative to "window" + * "event_mask" masks only interesting events + * "confine_to" limits the cursor movement to the specified window + * "cursor" changes the cursor for the duration of the grab + * "time" specifies the time + * + * Results: + * + * Side effects: + * requires a corresponding call to gdk_pointer_ungrab + * + *-------------------------------------------------------------- + */ + +gint +gdk_pointer_grab (GdkWindow * window, + gint owner_events, + GdkEventMask event_mask, + GdkWindow * confine_to, + GdkCursor * cursor, + guint32 time) +{ + /* From gdkwindow.c */ + extern int nevent_masks; + extern int event_mask_table[]; + + gint return_val; + GdkWindowPrivate *window_private; + GdkWindowPrivate *confine_to_private; + GdkCursorPrivate *cursor_private; + guint xevent_mask; + Window xwindow; + Window xconfine_to; + Cursor xcursor; + int i; + + g_return_val_if_fail (window != NULL, 0); + + window_private = (GdkWindowPrivate*) window; + confine_to_private = (GdkWindowPrivate*) confine_to; + cursor_private = (GdkCursorPrivate*) cursor; + + xwindow = window_private->xwindow; + + if (!confine_to) + xconfine_to = None; + else + xconfine_to = confine_to_private->xwindow; + + if (!cursor) + xcursor = None; + else + xcursor = cursor_private->xcursor; + + + xevent_mask = 0; + for (i = 0; i < nevent_masks; i++) + { + if (event_mask & (1 << (i + 1))) + xevent_mask |= event_mask_table[i]; + } + + if (((GdkWindowPrivate *)window)->extension_events && + gdk_input_vtable.grab_pointer) + return_val = gdk_input_vtable.grab_pointer (window, + owner_events, + event_mask, + confine_to, + time); + else + return_val = Success;; + + if (return_val == Success) + return_val = XGrabPointer (window_private->xdisplay, + xwindow, + owner_events, + xevent_mask, + GrabModeAsync, GrabModeAsync, + xconfine_to, + xcursor, + time); + + return return_val; +} + +/* + *-------------------------------------------------------------- + * gdk_pointer_ungrab + * + * Releases any pointer grab + * + * Arguments: + * + * Results: + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +void +gdk_pointer_ungrab (guint32 time) +{ + if (gdk_input_vtable.ungrab_pointer) + gdk_input_vtable.ungrab_pointer (time); + + XUngrabPointer (gdk_display, time); +} + +/* + *-------------------------------------------------------------- + * gdk_keyboard_grab + * + * Grabs the keyboard to a specific window + * + * Arguments: + * "window" is the window which will receive the grab + * "owner_events" specifies whether events will be reported as is, + * or relative to "window" + * "time" specifies the time + * + * Results: + * + * Side effects: + * requires a corresponding call to gdk_keyboard_ungrab + * + *-------------------------------------------------------------- + */ + +gint +gdk_keyboard_grab (GdkWindow * window, + gint owner_events, + guint32 time) +{ + GdkWindowPrivate *window_private; + Window xwindow; + + g_return_val_if_fail (window != NULL, 0); + + window_private = (GdkWindowPrivate*) window; + xwindow = window_private->xwindow; + + return XGrabKeyboard (window_private->xdisplay, + xwindow, + owner_events, + GrabModeAsync, GrabModeAsync, + time); +} + +/* + *-------------------------------------------------------------- + * gdk_keyboard_ungrab + * + * Releases any keyboard grab + * + * Arguments: + * + * Results: + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +void +gdk_keyboard_ungrab (guint32 time) +{ + XUngrabKeyboard (gdk_display, time); +} + +/* + *-------------------------------------------------------------- + * gdk_screen_width + * + * Return the width of the screen. + * + * Arguments: + * + * Results: + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +gint +gdk_screen_width () +{ + gint return_val; + + return_val = DisplayWidth (gdk_display, gdk_screen); + + return return_val; +} + +/* + *-------------------------------------------------------------- + * gdk_screen_height + * + * Return the height of the screen. + * + * Arguments: + * + * Results: + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +gint +gdk_screen_height () +{ + gint return_val; + + return_val = DisplayHeight (gdk_display, gdk_screen); + + return return_val; +} + +void +gdk_key_repeat_disable () +{ + XAutoRepeatOff (gdk_display); +} + +void +gdk_key_repeat_restore () +{ + if (autorepeat) + XAutoRepeatOn (gdk_display); + else + XAutoRepeatOff (gdk_display); +} + + +/* + *-------------------------------------------------------------- + * gdk_flush + * + * Flushes the Xlib output buffer and then waits + * until all requests have been received and processed + * by the X server. The only real use for this function + * is in dealing with XShm. + * + * Arguments: + * + * Results: + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +void gdk_flush () +{ + XSync (gdk_display, False); +} + + +void +gdk_beep () +{ + XBell(gdk_display, 100); +} + + +/* + *-------------------------------------------------------------- + * gdk_event_wait + * + * Waits until an event occurs or the timer runs out. + * + * Arguments: + * + * Results: + * Returns TRUE if an event is ready to be read and FALSE + * if the timer ran out. + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +static gint +gdk_event_wait () +{ + GList *list; + GdkInput *input; + GdkInputCondition condition; + SELECT_MASK readfds; + SELECT_MASK writefds; + SELECT_MASK exceptfds; + int max_input; + int nfd; + + /* If there are no events pending we will wait for an event. + * The time we wait is dependant on the "timer". If no timer + * has been specified then we'll block until an event arrives. + * If a timer has been specified we'll block until an event + * arrives or the timer expires. (This is all done using the + * "select" system call). + */ + + if (XPending (gdk_display) == 0) + { + FD_ZERO (&readfds); + FD_ZERO (&writefds); + FD_ZERO (&exceptfds); + + FD_SET (connection_number, &readfds); + max_input = connection_number; + + list = inputs; + while (list) + { + input = list->data; + list = list->next; + + if (input->condition & GDK_INPUT_READ) + FD_SET (input->source, &readfds); + if (input->condition & GDK_INPUT_WRITE) + FD_SET (input->source, &writefds); + if (input->condition & GDK_INPUT_EXCEPTION) + FD_SET (input->source, &exceptfds); + + max_input = MAX (max_input, input->source); + } + + nfd = select (max_input+1, &readfds, &writefds, &exceptfds, timerp); + + timerp = NULL; + timer_val = 0; + + if (nfd > 0) + { + if (FD_ISSET (connection_number, &readfds)) + { + if (XPending (gdk_display) == 0) + { + if (nfd == 1) + { + XNoOp (gdk_display); + XFlush (gdk_display); + } + return FALSE; + } + else + return TRUE; + } + + list = inputs; + while (list) + { + input = list->data; + list = list->next; + + condition = 0; + if (FD_ISSET (input->source, &readfds)) + condition |= GDK_INPUT_READ; + if (FD_ISSET (input->source, &writefds)) + condition |= GDK_INPUT_WRITE; + if (FD_ISSET (input->source, &exceptfds)) + condition |= GDK_INPUT_EXCEPTION; + + if (condition && input->function) + (* input->function) (input->data, input->source, condition); + } + } + } + else + return TRUE; + + return FALSE; +} + +static gint +gdk_event_translate (GdkEvent *event, + XEvent *xevent) +{ + + GdkWindow *window; + GdkWindowPrivate *window_private; + XComposeStatus compose; + int charcount; + char buf[16]; + gint return_val; + + /* Are static variables used for this purpose thread-safe? */ + static GdkPoint dnd_drag_start = {0,0}, + dnd_drag_oldpos = {0,0}; + static GdkRectangle dnd_drag_dropzone = {0,0,0,0}; + static gint dnd_drag_perhaps = 0; + static GdkWindowPrivate *real_sw = NULL; + static Window dnd_drag_curwin = None, dnd_drag_target = None; + + return_val = FALSE; + + /* Find the GdkWindow that this event occurred in. + * All events occur in some GdkWindow (otherwise, why + * would we be receiving them). It really is an error + * to receive an event for which we cannot find the + * corresponding GdkWindow. We handle events with window=None + * specially - they are generated by XFree86's XInput under + * some circumstances. + */ + + if ((xevent->xany.window == None) && + gdk_input_vtable.window_none_event) + { + return_val = gdk_input_vtable.window_none_event (event,xevent); + + if (return_val >= 0) /* was handled */ + return return_val; + else + return_val = FALSE; + } + + window = gdk_window_lookup (xevent->xany.window); + window_private = (GdkWindowPrivate *) window; + + /* 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. + */ + /* Addendum: + * During drag & drop you get events where the pointer is + * in other windows. Need to just do finer-grained checking + */ + switch (xevent->type) + { + case KeyPress: + /* Lookup the string corresponding to the given keysym. + */ + charcount = XLookupString (&xevent->xkey, buf, 16, + (KeySym*) &event->key.keyval, + &compose); + + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("key press:\t\twindow: %ld key: %12s %d\n", + xevent->xkey.window - base_id, + XKeysymToString (event->key.keyval), + event->key.keyval); + + event->key.type = GDK_KEY_PRESS; + event->key.window = window; + event->key.time = xevent->xkey.time; + event->key.state = (GdkModifierType) xevent->xkey.state; + + return_val = !window_private->destroyed; + break; + + case KeyRelease: + /* Lookup the string corresponding to the given keysym. + */ + charcount = XLookupString (&xevent->xkey, buf, 16, + (KeySym*) &event->key.keyval, + &compose); + + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("key release:\t\twindow: %ld key: %12s %d\n", + xevent->xkey.window - base_id, + 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; + + return_val = !window_private->destroyed; + break; + + case ButtonPress: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("button press[%d]:\t\twindow: %ld x,y: %d %d button: %d\n", + window_private?window_private->dnd_drag_enabled:0, + xevent->xbutton.window - base_id, + xevent->xbutton.x, xevent->xbutton.y, + xevent->xbutton.button); + + if (window_private && + (window_private->extension_events != 0) && + gdk_input_ignore_core) + break; + + event->button.type = GDK_BUTTON_PRESS; + event->button.window = window; + event->button.time = xevent->xbutton.time; + event->button.x = xevent->xbutton.x; + event->button.y = xevent->xbutton.y; + event->button.pressure = 0.5; + event->button.xtilt = 0; + event->button.ytilt = 0; + event->button.state = (GdkModifierType) xevent->xbutton.state; + event->button.button = xevent->xbutton.button; + event->button.source = GDK_SOURCE_MOUSE; + event->button.deviceid = GDK_CORE_POINTER; + + if ((event->button.time < (button_click_time[1] + TRIPLE_CLICK_TIME)) && + (event->button.window == button_window[1]) && + (event->button.button == button_number[1])) + { + 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; + } + else if ((event->button.time < (button_click_time[0] + DOUBLE_CLICK_TIME)) && + (event->button.window == button_window[0]) && + (event->button.button == button_number[0])) + { + 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; + } + else + { + 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; + } + if(window_private + && window_private->dnd_drag_enabled + && !dnd_drag_perhaps + && !gdk_dnd.drag_really) + { + dnd_drag_perhaps = 1; + dnd_drag_start.x = xevent->xbutton.x_root; + dnd_drag_start.y = xevent->xbutton.y_root; + real_sw = window_private; + + if(gdk_dnd.drag_startwindows) + { + g_free(gdk_dnd.drag_startwindows); + gdk_dnd.drag_startwindows = NULL; + } + gdk_dnd.drag_numwindows = gdk_dnd.drag_really = 0; + + { + /* Set motion mask for first DnD'd window, since it + will be the one that is actually dragged */ + XWindowAttributes dnd_winattr; + XSetWindowAttributes dnd_setwinattr; + Status rv; + + /* We need to get motion events while the button is down, so + we can know whether to really start dragging or not... */ + XGetWindowAttributes(gdk_display, (Window)window_private->xwindow, + &dnd_winattr); + + window_private->dnd_drag_savedeventmask = dnd_winattr.your_event_mask; + dnd_setwinattr.event_mask = + window_private->dnd_drag_eventmask = ButtonMotionMask; + XChangeWindowAttributes(gdk_display, window_private->xwindow, + CWEventMask, &dnd_setwinattr); + } + } + return_val = window_private?(!window_private->destroyed):FALSE; + break; + + case ButtonRelease: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("button release[%d]:\twindow: %ld x,y: %d %d button: %d\n", + window_private?window_private->dnd_drag_enabled:0, + xevent->xbutton.window - base_id, + xevent->xbutton.x, xevent->xbutton.y, + xevent->xbutton.button); + + if (window_private && + (window_private->extension_events != 0) && + gdk_input_ignore_core) + break; + + event->button.type = GDK_BUTTON_RELEASE; + event->button.window = window; + event->button.time = xevent->xbutton.time; + event->button.x = xevent->xbutton.x; + event->button.y = xevent->xbutton.y; + event->button.pressure = 0.5; + event->button.xtilt = 0; + event->button.ytilt = 0; + event->button.state = (GdkModifierType) xevent->xbutton.state; + event->button.button = xevent->xbutton.button; + event->button.source = GDK_SOURCE_MOUSE; + event->button.deviceid = GDK_CORE_POINTER; + + if(dnd_drag_perhaps) + { + if(gdk_dnd.drag_really) + { + GdkPoint foo = {xevent->xbutton.x_root, + xevent->xbutton.y_root}; + XUngrabPointer(gdk_display, CurrentTime); + + if(dnd_drag_target != None) + gdk_dnd_drag_end(dnd_drag_target, foo); + gdk_dnd.drag_really = 0; + + if(gdk_dnd.drag_numwindows) + { + XSetWindowAttributes attrs; + /* Reset event mask to pre-drag value, assuming event_mask + doesn't change during drag */ + attrs.event_mask = real_sw->dnd_drag_savedeventmask; + XChangeWindowAttributes(gdk_display, real_sw->xwindow, + CWEventMask, &attrs); + } + + gdk_dnd.drag_numwindows = 0; + if(gdk_dnd.drag_startwindows) + { + g_free(gdk_dnd.drag_startwindows); + gdk_dnd.drag_startwindows = NULL; + } + + real_sw = NULL; + } + + dnd_drag_perhaps = 0; + dnd_drag_start.x = dnd_drag_start.y = 0; + dnd_drag_dropzone.x = dnd_drag_dropzone.y = 0; + dnd_drag_dropzone.width = dnd_drag_dropzone.height = 0; + dnd_drag_curwin = None; + } + return_val = window ? (!window_private->destroyed) : FALSE; + break; + + case MotionNotify: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("motion notify:\t\twindow: %ld x,y: %d %d hint: %s d:%d r%d\n", + xevent->xmotion.window - base_id, + xevent->xmotion.x, xevent->xmotion.y, + (xevent->xmotion.is_hint) ? "true" : "false", + dnd_drag_perhaps, gdk_dnd.drag_really); + + if (window_private && + (window_private->extension_events != 0) && + gdk_input_ignore_core) + break; + + event->motion.type = GDK_MOTION_NOTIFY; + event->motion.window = window; + event->motion.time = xevent->xmotion.time; + event->motion.x = xevent->xmotion.x; + event->motion.y = xevent->xmotion.y; + event->motion.pressure = 0.5; + event->motion.xtilt = 0; + event->motion.ytilt = 0; + event->motion.state = (GdkModifierType) xevent->xmotion.state; + event->motion.is_hint = xevent->xmotion.is_hint; + event->motion.source = GDK_SOURCE_MOUSE; + event->motion.deviceid = GDK_CORE_POINTER; + +#define IS_IN_ZONE(cx, cy) (cx >= dnd_drag_dropzone.x \ + && cy >= dnd_drag_dropzone.y \ + && cx < (dnd_drag_dropzone.x + dnd_drag_dropzone.width) \ + && cy < (dnd_drag_dropzone.y + dnd_drag_dropzone.height)) + + if(dnd_drag_perhaps && gdk_dnd.drag_really) + { + /* First, we have to find what window the motion was in... */ + /* XXX there has to be a better way to do this, perhaps with + XTranslateCoordinates or XQueryTree - I don't know how, + and this sort of works */ + Window curwin, childwin = gdk_root_window, rootwinret; + int x, y; + unsigned int mask; + while(childwin != None) + { + curwin = childwin; + XQueryPointer(gdk_display, curwin, &rootwinret, &childwin, + &x, &y, &x, &y, &mask); + } + if(curwin != dnd_drag_curwin) + { + /* We have left one window and entered another + (do leave & enter bits) */ + if(dnd_drag_curwin != real_sw->xwindow && dnd_drag_curwin != None) + gdk_dnd_drag_leave(dnd_drag_curwin); + dnd_drag_curwin = curwin; + gdk_dnd_drag_enter(dnd_drag_curwin); + dnd_drag_dropzone.x = dnd_drag_dropzone.y = 0; + dnd_drag_dropzone.width = dnd_drag_dropzone.height = 0; + dnd_drag_target = None; + XChangeActivePointerGrab(gdk_display, + ButtonMotionMask | + ButtonPressMask | ButtonReleaseMask | + EnterWindowMask | LeaveWindowMask, + gdk_dnd.gdk_cursor_dragdefault, + CurrentTime); + } + else if(dnd_drag_dropzone.width > 0 + && dnd_drag_dropzone.height > 0) + { + /* Handle all that dropzone stuff - thanks John ;-) */ + if(dnd_drag_target != None + && IS_IN_ZONE(dnd_drag_oldpos.x, dnd_drag_oldpos.y) + && !IS_IN_ZONE(xevent->xmotion.x_root, + xevent->xmotion.y_root)) + { + /* We were in the drop zone and moved out */ + dnd_drag_target = None; + gdk_dnd_drag_leave(curwin); + } + else + { + /* We were outside drop zone but in the window + - have to send enter events */ + gdk_dnd_drag_enter(curwin); + dnd_drag_curwin = curwin; + dnd_drag_dropzone.x = dnd_drag_dropzone.y = 0; + dnd_drag_target = None; + } + } else + dnd_drag_curwin = None; + return_val = FALSE; + } + else + return_val = window?(!window_private->destroyed):FALSE; + break; + + case EnterNotify: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("enter notify:\t\twindow: %ld detail: %d subwin: %ld\n", + xevent->xcrossing.window - base_id, + xevent->xcrossing.detail, + xevent->xcrossing.subwindow - base_id); + + /* Tell XInput stuff about it if appropriate */ + if (window_private && + (window_private->extension_events != 0) && + gdk_input_vtable.enter_event) + gdk_input_vtable.enter_event (&xevent->xcrossing, window); + + 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) + event->crossing.subwindow = gdk_window_lookup (xevent->xcrossing.subwindow); + else + event->crossing.subwindow = NULL; + + /* Translate the crossing detail into Gdk terms. + */ + switch (xevent->xcrossing.detail) + { + case NotifyInferior: + event->crossing.detail = GDK_NOTIFY_INFERIOR; + break; + case NotifyAncestor: + event->crossing.detail = GDK_NOTIFY_ANCESTOR; + break; + case NotifyVirtual: + event->crossing.detail = GDK_NOTIFY_VIRTUAL; + break; + case NotifyNonlinear: + event->crossing.detail = GDK_NOTIFY_NONLINEAR; + break; + case NotifyNonlinearVirtual: + event->crossing.detail = GDK_NOTIFY_NONLINEAR_VIRTUAL; + break; + default: + event->crossing.detail = GDK_NOTIFY_UNKNOWN; + break; + } + + if(dnd_drag_perhaps + && gdk_dnd.drag_really + && xevent->xcrossing.window == real_sw->xwindow) + { + gdk_dnd.drag_really = 0; + XUngrabPointer(gdk_display, CurrentTime); + } + + return_val = (window ? !window_private->destroyed : FALSE); + break; + + case LeaveNotify: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("leave notify:\t\twindow: %ld detail: %d subwin: %ld\n", + xevent->xcrossing.window - base_id, + xevent->xcrossing.detail, xevent->xcrossing.subwindow - base_id); + + event->crossing.type = GDK_LEAVE_NOTIFY; + event->crossing.window = window; + + /* Translate the crossing detail into Gdk terms. + */ + switch (xevent->xcrossing.detail) + { + case NotifyInferior: + event->crossing.detail = GDK_NOTIFY_INFERIOR; + break; + case NotifyAncestor: + event->crossing.detail = GDK_NOTIFY_ANCESTOR; + break; + case NotifyVirtual: + event->crossing.detail = GDK_NOTIFY_VIRTUAL; + break; + case NotifyNonlinear: + event->crossing.detail = GDK_NOTIFY_NONLINEAR; + break; + case NotifyNonlinearVirtual: + event->crossing.detail = GDK_NOTIFY_NONLINEAR_VIRTUAL; + break; + default: + event->crossing.detail = GDK_NOTIFY_UNKNOWN; + break; + } + if(dnd_drag_perhaps + && !gdk_dnd.drag_really) + { + gdk_dnd_drag_addwindow((GdkWindow *) real_sw); + gdk_dnd_drag_begin((GdkWindow *) real_sw); + XGrabPointer(gdk_display, real_sw->xwindow, False, + ButtonMotionMask | + ButtonPressMask | ButtonReleaseMask | + EnterWindowMask | LeaveWindowMask, + GrabModeAsync, GrabModeAsync, gdk_root_window, + gdk_dnd.gdk_cursor_dragdefault, CurrentTime); + gdk_dnd.drag_really = 1; + } + return_val = window ? (!window_private->destroyed) : FALSE; + break; + + case FocusIn: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("focus in:\t\twindow: %ld\n", + xevent->xfocus.window - base_id); + + event->focus_change.type = GDK_FOCUS_CHANGE; + event->focus_change.window = window; + event->focus_change.in = TRUE; + + return_val = !window_private->destroyed; + break; + + case FocusOut: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("focus out:\t\twindow: %ld\n", + xevent->xfocus.window - base_id); + + event->focus_change.type = GDK_FOCUS_CHANGE; + event->focus_change.window = window; + event->focus_change.in = FALSE; + + return_val = !window_private->destroyed; + break; + + case KeymapNotify: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("keymap notify\n"); + + /* Not currently handled */ + break; + + case Expose: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("expose:\t\twindow: %ld %d x,y: %d %d w,h: %d %d\n", + xevent->xexpose.window - base_id, xevent->xexpose.count, + xevent->xexpose.x, xevent->xexpose.y, + xevent->xexpose.width, xevent->xexpose.height); + + event->expose.type = GDK_EXPOSE; + event->expose.window = window; + event->expose.area.x = xevent->xexpose.x; + event->expose.area.y = xevent->xexpose.y; + event->expose.area.width = xevent->xexpose.width; + event->expose.area.height = xevent->xexpose.height; + event->expose.count = xevent->xexpose.count; + + return_val = !window_private->destroyed; + break; + + case GraphicsExpose: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("graphics expose:\tdrawable: %ld\n", + xevent->xgraphicsexpose.drawable - base_id); + + event->expose.type = GDK_EXPOSE; + event->expose.window = window; + event->expose.area.x = xevent->xgraphicsexpose.x; + event->expose.area.y = xevent->xgraphicsexpose.y; + event->expose.area.width = xevent->xgraphicsexpose.width; + event->expose.area.height = xevent->xgraphicsexpose.height; + event->expose.count = xevent->xexpose.count; + + return_val = !window_private->destroyed; + break; + + case NoExpose: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("no expose:\t\tdrawable: %ld\n", + xevent->xnoexpose.drawable - base_id); + + /* Not currently handled */ + break; + + case VisibilityNotify: + /* Print debugging info. + */ + if (gdk_show_events) + switch (xevent->xvisibility.state) + { + case VisibilityFullyObscured: + g_print ("visibility notify:\twindow: %ld none\n", + xevent->xvisibility.window - base_id); + break; + case VisibilityPartiallyObscured: + g_print ("visibility notify:\twindow: %ld partial\n", + xevent->xvisibility.window - base_id); + break; + case VisibilityUnobscured: + g_print ("visibility notify:\twindow: %ld full\n", + xevent->xvisibility.window - base_id); + break; + } + + /* Not currently handled */ + break; + + case CreateNotify: + /* Not currently handled */ + break; + + case DestroyNotify: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("destroy notify:\twindow: %ld\n", + xevent->xdestroywindow.window - base_id); + + event->any.type = GDK_DESTROY; + event->any.window = window; + + /* Remeber which window received the destroy notify + * event so that we can destroy our associated + * data structures the next time the user asks + * us for an event. + */ + received_destroy_notify = TRUE; + window_to_destroy = window; + + return_val = !window_private->destroyed; + break; + + case UnmapNotify: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("unmap notify:\t\twindow: %ld\n", + xevent->xmap.window - base_id); + + event->any.type = GDK_UNMAP; + event->any.window = window; + + return_val = !window_private->destroyed; + break; + + case MapNotify: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("map notify:\t\twindow: %ld\n", + xevent->xmap.window - base_id); + + event->any.type = GDK_MAP; + event->any.window = window; + + return_val = !window_private->destroyed; + break; + + case ReparentNotify: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("reparent notify:\twindow: %ld\n", + xevent->xreparent.window - base_id); + + /* Not currently handled */ + break; + + case ConfigureNotify: + /* Print debugging info. + */ + while ((XPending(gdk_display) > 0) && + XCheckTypedWindowEvent(gdk_display, xevent->xany.window, + ConfigureNotify, xevent)) + /*XSync(gdk_display, 0)*/; + + if (gdk_show_events) + g_print ("configure notify:\twindow: %ld x,y: %d %d w,h: %d %d\n", + xevent->xconfigure.window - base_id, + xevent->xconfigure.x, xevent->xconfigure.y, + xevent->xconfigure.width, xevent->xconfigure.height); + + if (window_private && + (window_private->extension_events != 0) && + gdk_input_vtable.configure_event) + gdk_input_vtable.configure_event (&xevent->xconfigure, window); + + if ((window_private->window_type != GDK_WINDOW_CHILD) && + ((window_private->width != xevent->xconfigure.width) || + (window_private->height != xevent->xconfigure.height))) + { + event->configure.type = GDK_CONFIGURE; + event->configure.window = window; + event->configure.x = xevent->xconfigure.x; + event->configure.y = xevent->xconfigure.y; + event->configure.width = xevent->xconfigure.width; + event->configure.height = xevent->xconfigure.height; + + window_private->x = xevent->xconfigure.x; + window_private->y = xevent->xconfigure.y; + window_private->width = xevent->xconfigure.width; + window_private->height = xevent->xconfigure.height; + if (window_private->resize_count > 1) + window_private->resize_count -= 1; + + return_val = !window_private->destroyed; + } + break; + + case PropertyNotify: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("property notify:\twindow: %ld\n", + xevent->xproperty.window - base_id); + + event->property.type = GDK_PROPERTY_NOTIFY; + event->property.window = window; + event->property.atom = xevent->xproperty.atom; + event->property.time = xevent->xproperty.time; + event->property.state = xevent->xproperty.state; + + return_val = !window_private->destroyed; + break; + + case SelectionClear: + if (gdk_show_events) + g_print ("selection clear:\twindow: %ld\n", + xevent->xproperty.window - base_id); + + event->selection.type = GDK_SELECTION_CLEAR; + event->selection.window = window; + event->selection.selection = xevent->xselectionclear.selection; + event->selection.time = xevent->xselectionclear.time; + + return_val = !((GdkWindowPrivate*) window)->destroyed; + break; + + case SelectionRequest: + if (gdk_show_events) + g_print ("selection request:\twindow: %ld\n", + xevent->xproperty.window - base_id); + + event->selection.type = GDK_SELECTION_REQUEST; + event->selection.window = window; + event->selection.selection = xevent->xselectionrequest.selection; + event->selection.target = xevent->xselectionrequest.target; + event->selection.property = xevent->xselectionrequest.property; + event->selection.requestor = xevent->xselectionrequest.requestor; + event->selection.time = xevent->xselectionrequest.time; + + return_val = !((GdkWindowPrivate*) window)->destroyed; + break; + + case SelectionNotify: + if (gdk_show_events) + g_print ("selection notify:\twindow: %ld\n", + xevent->xproperty.window - base_id); + + + event->selection.type = GDK_SELECTION_NOTIFY; + event->selection.window = window; + event->selection.selection = xevent->xselection.selection; + event->selection.target = xevent->xselection.target; + event->selection.property = xevent->xselection.property; + event->selection.time = xevent->xselection.time; + + return_val = !((GdkWindowPrivate*) window)->destroyed; + break; + + case ColormapNotify: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("colormap notify:\twindow: %ld\n", + xevent->xcolormap.window - base_id); + + /* Not currently handled */ + break; + + case ClientMessage: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("client message:\twindow: %ld\n", + xevent->xclient.window - base_id); + + /* Client messages are the means of the window manager + * communicating with a program. We'll first check to + * see if this is really the window manager talking + * to us. + */ + if (xevent->xclient.message_type == gdk_wm_protocols) + { + if ((Atom) xevent->xclient.data.l[0] == gdk_wm_delete_window) + { + /* The delete window request specifies a window + * to delete. We don't actually destroy the + * window because "it is only a request". (The + * window might contain vital data that the + * program does not want destroyed). Instead + * the event is passed along to the program, + * which should then destroy the window. + */ + + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("delete window:\t\twindow: %ld\n", + xevent->xclient.window - base_id); + + event->any.type = GDK_DELETE; + event->any.window = window; + + return_val = !window_private->destroyed; + } + else if ((Atom) xevent->xclient.data.l[0] == gdk_wm_take_focus) + { + } + } + else if (xevent->xclient.message_type == gdk_dnd.gdk_XdeEnter) + { + Atom reptype = 0; + + event->dropenter.u.allflags = xevent->xclient.data.l[1]; + if (gdk_show_events) + g_print ("GDK_DROP_ENTER\n"); + return_val = FALSE; + + /* Now figure out if we really want this drop... + * If someone is trying funky clipboard stuff, ignore + */ + if (window_private + && window_private->dnd_drop_enabled + && event->dropenter.u.flags.sendreply + && (reptype = gdk_dnd_check_types (window, xevent))) + { + XEvent replyev; + + replyev.xclient.type = ClientMessage; + replyev.xclient.window = xevent->xclient.data.l[0]; + replyev.xclient.format = 32; + replyev.xclient.message_type = gdk_dnd.gdk_XdeRequest; + replyev.xclient.data.l[0] = window_private->xwindow; + + event->dragrequest.u.allflags = 0; + event->dragrequest.u.flags.protocol_version = + DND_PROTOCOL_VERSION; + event->dragrequest.u.flags.willaccept = 1; + event->dragrequest.u.flags.delete_data = + (window_private->dnd_drop_destructive_op) ? 1 : 0; + + replyev.xclient.data.l[1] = event->dragrequest.u.allflags; + replyev.xclient.data.l[2] = replyev.xclient.data.l[3] = 0; + replyev.xclient.data.l[4] = reptype; + + XSendEvent (gdk_display, replyev.xclient.window, + False, NoEventMask, &replyev); + + event->any.type = GDK_DROP_ENTER; + event->dropenter.requestor = replyev.xclient.window; + event->dropenter.u.allflags = xevent->xclient.data.l[1]; + } + } + else if (xevent->xclient.message_type == gdk_dnd.gdk_XdeLeave) + { + if (gdk_show_events) + g_print ("GDK_DROP_LEAVE\n"); + if (window_private && window_private->dnd_drop_enabled) + { + event->dropleave.type = GDK_DROP_LEAVE; + event->dropleave.window = window; + event->dropleave.requestor = xevent->xclient.data.l[0]; + event->dropleave.u.allflags = xevent->xclient.data.l[1]; + return_val = TRUE; + } + else + return_val = FALSE; + } + else if (xevent->xclient.message_type == gdk_dnd.gdk_XdeRequest) + { + /* + * make sure to only handle requests from the window the cursor is + * over + */ + if (gdk_show_events) + g_print ("GDK_DRAG_REQUEST\n"); + event->dragrequest.u.allflags = xevent->xclient.data.l[1]; + return_val = FALSE; + + if (window && gdk_dnd.drag_really && + xevent->xclient.data.l[0] == dnd_drag_curwin && + event->dragrequest.u.flags.sendreply == 0) + { + /* Got request - do we need to ask user? */ + if (!event->dragrequest.u.flags.willaccept + && event->dragrequest.u.flags.senddata) + { + /* Yes we do :) */ + event->dragrequest.type = GDK_DRAG_REQUEST; + event->dragrequest.window = window; + event->dragrequest.requestor = xevent->xclient.data.l[0]; + event->dragrequest.isdrop = 0; + event->dragrequest.drop_coords.x = + event->dragrequest.drop_coords.y = 0; + return_val = TRUE; + } + else if (event->dragrequest.u.flags.willaccept) + { + window_private->dnd_drag_destructive_op = + event->dragrequest.u.flags.delete_data; + window_private->dnd_drag_accepted = 1; + window_private->dnd_drag_data_type = + xevent->xclient.data.l[4]; + + dnd_drag_target = dnd_drag_curwin; + XChangeActivePointerGrab (gdk_display, + ButtonMotionMask | + ButtonPressMask | + ButtonReleaseMask | + EnterWindowMask | LeaveWindowMask, + gdk_dnd.gdk_cursor_dragok, + CurrentTime); + } + dnd_drag_dropzone.x = xevent->xclient.data.l[2] & 65535; + dnd_drag_dropzone.y = + (xevent->xclient.data.l[2] >> 16) & 65535; + dnd_drag_dropzone.width = xevent->xclient.data.l[3] & 65535; + dnd_drag_dropzone.height = + (xevent->xclient.data.l[3] >> 16) & 65535; + } + } + else if(xevent->xclient.message_type == gdk_dnd.gdk_XdeDataAvailable) + { + gint tmp_int; Atom tmp_atom; + gulong tmp_long; + guchar *tmp_charptr; + gpointer tmp_ptr; + + if(gdk_show_events) + g_print("GDK_DROP_DATA_AVAIL\n"); + event->dropdataavailable.u.allflags = xevent->xclient.data.l[1]; + if(window + /* No preview of data ATM */ + && event->dropdataavailable.u.flags.isdrop) + { + event->dropdataavailable.type = GDK_DROP_DATA_AVAIL; + event->dropdataavailable.window = window; + event->dropdataavailable.requestor = xevent->xclient.data.l[0]; + event->dropdataavailable.data_type = + gdk_atom_name(xevent->xclient.data.l[2]); + if(XGetWindowProperty (gdk_display, + event->dropdataavailable.requestor, + xevent->xclient.data.l[2], + 0, LONG_MAX - 1, + False, XA_PRIMARY, &tmp_atom, + &tmp_int, + &event->dropdataavailable.data_numbytes, + &tmp_long, + &tmp_charptr) + != Success) + { + g_warning("XGetWindowProperty on %#x may have failed\n", + event->dropdataavailable.requestor); + event->dropdataavailable.data = NULL; + } + else + { + g_print("XGetWindowProperty got us %d bytes\n", + event->dropdataavailable.data_numbytes); + event->dropdataavailable.data = + g_malloc(event->dropdataavailable.data_numbytes); + memcpy(event->dropdataavailable.data, + tmp_charptr, event->dropdataavailable.data_numbytes); + XFree(tmp_charptr); + return_val = TRUE; + } + return_val = TRUE; + } + } else { + /* Send unknown ClientMessage's on to Gtk for it to use */ + event->client.type = GDK_CLIENT_EVENT; + event->client.window = window; + event->client.message_type = xevent->xclient.message_type; + event->client.data_format = xevent->xclient.format; + memcpy(&event->client.data, &xevent->xclient.data, + sizeof(event->client.data)); + return_val = TRUE; + } + return_val = return_val && !window_private->destroyed; + break; + + case MappingNotify: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("mapping notify\n"); + + /* Let XLib know that there is a new keyboard mapping. + */ + XRefreshKeyboardMapping (&xevent->xmapping); + break; + + default: + /* something else - (e.g., a Xinput event) */ + + if (window_private && + (window_private->extension_events != 0) && + gdk_input_vtable.other_event) + return_val = gdk_input_vtable.other_event(event, xevent, window); + + if (return_val < 0) /* not an XInput event, convert */ + { + event->other.type = GDK_OTHER_EVENT; + event->other.window = window; + event->other.xevent = &other_xevent[other_xevent_i]; + memcpy (&other_xevent[other_xevent_i], xevent, sizeof (XEvent)); + other_xevent_i = (other_xevent_i+1) % OTHER_XEVENT_BUFSIZE; + return_val = TRUE; + } + + return_val = return_val && !window_private->destroyed; + break; + } + + return return_val; +} + +static Bool +gdk_event_get_type (Display *display, + XEvent *xevent, + XPointer arg) +{ + GdkEvent event; + GdkPredicate *pred; + + if (gdk_event_translate (&event, xevent)) + { + pred = (GdkPredicate*) arg; + return (* pred->func) (&event, pred->data); + } + + return FALSE; +} + +static void +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); +} + +/* + *-------------------------------------------------------------- + * gdk_exit_func + * + * This is the "atexit" function that makes sure the + * library gets a chance to cleanup. + * + * Arguments: + * + * Results: + * + * Side effects: + * The library is un-initialized and the program exits. + * + *-------------------------------------------------------------- + */ + +static void +gdk_exit_func () +{ + if (initialized) + { + gdk_image_exit (); + gdk_input_exit (); + gdk_key_repeat_restore (); + + XCloseDisplay (gdk_display); + initialized = 0; + } +} + +/* + *-------------------------------------------------------------- + * gdk_x_error + * + * The X error handling routine. + * + * Arguments: + * "display" is the X display the error orignated from. + * "error" is the XErrorEvent that we are handling. + * + * Results: + * Either we were expecting some sort of error to occur, + * in which case we set the "gdk_error_code" flag, or this + * error was unexpected, in which case we will print an + * error message and exit. (Since trying to continue will + * most likely simply lead to more errors). + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +static int +gdk_x_error (Display *display, + XErrorEvent *error) +{ + char buf[64]; + + if (gdk_error_warnings) + { + XGetErrorText (display, error->error_code, buf, 63); + g_error ("%s", buf); + } + + gdk_error_code = -1; + return 0; +} + +/* + *-------------------------------------------------------------- + * gdk_x_io_error + * + * The X I/O error handling routine. + * + * Arguments: + * "display" is the X display the error orignated from. + * + * Results: + * An X I/O error basically means we lost our connection + * to the X server. There is not much we can do to + * continue, so simply print an error message and exit. + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +static int +gdk_x_io_error (Display *display) +{ + g_error ("an x io error occurred"); + return 0; +} + +/* + *-------------------------------------------------------------- + * gdk_signal + * + * The signal handler. + * + * Arguments: + * "sig_num" is the number of the signal we received. + * + * Results: + * The signals we catch are all fatal. So we simply build + * up a nice little error message and print it and exit. + * If in the process of doing so another signal is received + * we notice that we are already exiting and simply kill + * our process. + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +static RETSIGTYPE +gdk_signal (int sig_num) +{ + static int caught_fatal_sig = 0; + char *sig; + + if (caught_fatal_sig) + kill (getpid (), sig_num); + caught_fatal_sig = 1; + + switch (sig_num) + { + case SIGHUP: + sig = "sighup"; + break; + case SIGINT: + sig = "sigint"; + break; + case SIGQUIT: + sig = "sigquit"; + break; + case SIGBUS: + sig = "sigbus"; + break; + case SIGSEGV: + sig = "sigsegv"; + break; + case SIGPIPE: + sig = "sigpipe"; + break; + case SIGTERM: + sig = "sigterm"; + break; + default: + sig = "unknown signal"; + break; + } + + g_print ("\n** ERROR **: %s caught\n", sig); + gdk_exit (1); +} + +static void +gdk_dnd_drag_begin (GdkWindow *initial_window) +{ + GdkEventDragBegin tev; + tev.type = GDK_DRAG_BEGIN; + tev.window = initial_window; + tev.u.allflags = 0; + tev.u.flags.protocol_version = DND_PROTOCOL_VERSION; + + gdk_event_put ((GdkEvent *) &tev); +} + +static void +gdk_dnd_drag_enter (Window dest) +{ + XEvent sev; + GdkEventDropEnter tev; + int i; + GdkWindowPrivate *wp; + + sev.xclient.type = ClientMessage; + sev.xclient.format = 32; + sev.xclient.message_type = gdk_dnd.gdk_XdeEnter; + sev.xclient.window = dest; + + tev.u.allflags = 0; + tev.u.flags.protocol_version = DND_PROTOCOL_VERSION; + tev.u.flags.sendreply = 1; + for (i = 0; i < gdk_dnd.drag_numwindows; i++) + { + wp = (GdkWindowPrivate *) gdk_dnd.drag_startwindows[i]; + if (wp->dnd_drag_data_numtypesavail) + { + sev.xclient.data.l[0] = wp->xwindow; + tev.u.flags.extended_typelist = (wp->dnd_drag_data_numtypesavail > 3)?1:0; + sev.xclient.data.l[1] = tev.u.allflags; + sev.xclient.data.l[2] = wp->dnd_drag_data_typesavail[0]; + if (wp->dnd_drag_data_numtypesavail > 1) + { + sev.xclient.data.l[3] = wp->dnd_drag_data_typesavail[1]; + if (wp->dnd_drag_data_numtypesavail > 2) + { + sev.xclient.data.l[4] = wp->dnd_drag_data_typesavail[2]; + } + else + sev.xclient.data.l[4] = None; + } + else + sev.xclient.data.l[3] = sev.xclient.data.l[4] = None; + XSendEvent (gdk_display, dest, False, NoEventMask, &sev); + } + + } +} + +static void +gdk_dnd_drag_leave (Window dest) +{ + XEvent sev; + GdkEventDropLeave tev; + int i; + GdkWindowPrivate *wp; + + tev.u.allflags = 0; + + tev.u.flags.protocol_version = DND_PROTOCOL_VERSION; + sev.xclient.type = ClientMessage; + sev.xclient.window = dest; + sev.xclient.format = 32; + sev.xclient.message_type = gdk_dnd.gdk_XdeLeave; + sev.xclient.data.l[1] = tev.u.allflags; + for (i = 0; i < gdk_dnd.drag_numwindows; i++) + { + wp = (GdkWindowPrivate *) gdk_dnd.drag_startwindows[i]; + sev.xclient.data.l[0] = wp->xwindow; + XSendEvent(gdk_display, dest, False, NoEventMask, &sev); + wp->dnd_drag_accepted = 0; + } +} + +/* + * when a drop occurs, we go through the list of windows being dragged and + * tell them that it has occurred, so that they can set things up and reply + * to 'dest' window + */ +static void +gdk_dnd_drag_end (Window dest, + GdkPoint coords) +{ + GdkWindowPrivate *wp; + GdkEventDragRequest tev; + gchar *tmp_cptr; + int i; + + tev.type = GDK_DRAG_REQUEST; + tev.drop_coords = coords; + tev.requestor = dest; + tev.u.allflags = 0; + tev.u.flags.protocol_version = DND_PROTOCOL_VERSION; + tev.isdrop = 1; + + for (i = 0; i < gdk_dnd.drag_numwindows; i++) + { + wp = (GdkWindowPrivate *) gdk_dnd.drag_startwindows[i]; + if (wp->dnd_drag_accepted) + { + tev.window = (GdkWindow *) wp; + tev.u.flags.delete_data = wp->dnd_drag_destructive_op; + tev.data_type = + gdk_atom_name(wp->dnd_drag_data_type); + + gdk_event_put((GdkEvent *) &tev); + } + } +} + +static GdkAtom +gdk_dnd_check_types (GdkWindow *window, + XEvent *xevent) +{ + GdkWindowPrivate *wp = (GdkWindowPrivate *) window; + int i, j; + GdkEventDropEnter event; + + g_return_val_if_fail(window != NULL, 0); + g_return_val_if_fail(xevent != NULL, 0); + g_return_val_if_fail(xevent->type == ClientMessage, 0); + g_return_val_if_fail(xevent->xclient.message_type == gdk_dnd.gdk_XdeEnter, 0); + + if(wp->dnd_drop_data_numtypesavail <= 0 || + !wp->dnd_drop_data_typesavail) + return 0; + + for (i = 2; i <= 4; i++) + { + for (j = 0; j < wp->dnd_drop_data_numtypesavail; j++) + { + if (xevent->xclient.data.l[i] == wp->dnd_drop_data_typesavail[j]) + return xevent->xclient.data.l[i]; + } + } + + /* Now we get the extended type list if it's available */ + event.u.allflags = xevent->xclient.data.l[1]; + if (event.u.flags.extended_typelist) + { + Atom *exttypes, realtype; + gulong nitems, nbar; + gint realfmt; + + if (XGetWindowProperty(gdk_display, xevent->xclient.data.l[0], + gdk_dnd.gdk_XdeTypelist, 0L, LONG_MAX - 1, + False, AnyPropertyType, &realtype, &realfmt, + &nitems, &nbar, (unsigned char **) &exttypes) + != Success) + return 0; + + if (realfmt != (sizeof(Atom) * 8)) + { + g_warning("XdeTypelist property had format of %d instead of the expected %d, on window %#lx\n", + realfmt, sizeof(Atom) * 8, xevent->xclient.data.l[0]); + return 0; + } + + for (i = 0; i <= nitems; i++) + { + for (j = 0; j < wp->dnd_drop_data_numtypesavail; j++) + { + if (exttypes[i] == wp->dnd_drop_data_typesavail[j]) + { + XFree (exttypes); + return exttypes[i]; + } + } + } + XFree (exttypes); + } + return 0; +} + +/* + * used for debugging only + */ +static void +gdk_print_atom (GdkAtom anatom) +{ + gchar *tmpstr = NULL; + tmpstr = (anatom!=None)?gdk_atom_name(anatom):"(none)"; + g_print("Atom %lu has name %s\n", anatom, tmpstr); + if(tmpstr) + g_free(tmpstr); +} + +/* + * used only by below routine and itself + */ +static Window +getchildren (Display *dpy, + Window win, + Atom WM_STATE) +{ + Window root, parent, *children, inf = 0; + Atom type = None; + unsigned int nchildren, i; + int format; + unsigned long nitems, after; + unsigned char *data; + + if (XQueryTree(dpy, win, &root, &parent, &children, &nchildren) == 0) + return 0; + + for (i = 0; !inf && (i < nchildren); i++) + { + XGetWindowProperty (dpy, children[i], WM_STATE, 0, 0, False, + AnyPropertyType, &type, &format, &nitems, + &after, &data); + if (type != 0) + inf = children[i]; + } + + for (i = 0; !inf && (i < nchildren); i++) + inf = getchildren (dpy, children[i], WM_STATE); + + if (children != 0) + XFree ((char *) children); + + return inf; +} + +/* + * find a window with WM_STATE, else return win itself, as per ICCCM + * + * modification of the XmuClientWindow() routine from X11R6.3 + */ +Window +gdk_get_client_window (Display *dpy, + Window win) +{ + Atom WM_STATE; + Atom type = None; + int format; + unsigned long nitems, after; + unsigned char *data; + Window inf; + + if (win == 0) + return DefaultRootWindow(dpy); + + if ((WM_STATE = XInternAtom (dpy, "WM_STATE", True)) == 0) + return win; + + XGetWindowProperty (dpy, win, WM_STATE, 0, 0, False, AnyPropertyType, + &type, &format, &nitems, &after, &data); + if (type) + return win; + + inf = getchildren (dpy, win, WM_STATE); + + if (inf == 0) + return win; + else + return inf; +} + +static GdkWindow * +gdk_drop_get_real_window (GdkWindow *w, + guint16 *x, + guint16 *y) +{ + GdkWindow *retval = w; + GdkWindowPrivate *awin; + GList *children; + gint16 myx = *x, myy = *y; + + g_return_val_if_fail(w != NULL && x != NULL && y != NULL, NULL); + + myx = *x; + myy = *y; + +descend: + for (children = gdk_window_get_children(retval); + children && children->next; + children = children->next) + { + awin = (GdkWindowPrivate *) children->data; + if ((myx >= awin->x) && (myy >= awin->y) + && (myx < (awin->x + awin->width)) + && (myy < (awin->y + awin->height))) + { + retval = (GdkWindow *) awin; + myx -= awin->x; + myy -= awin->y; + goto descend; + } + } + + *x = myx; + *y = myy; + + return retval; +} + +/* Sends a ClientMessage to all toplevel client windows */ +void +gdk_event_send_clientmessage_toall(GdkEvent *event) +{ + XEvent sev; + Window *ret_children, ret_root, ret_parent, curwin; + unsigned int ret_nchildren; + int i; + + g_return_if_fail(event != NULL); + + /* Set up our event to send, with the exception of its target window */ + sev.xclient.type = ClientMessage; + sev.xclient.display = gdk_display; + sev.xclient.format = event->client.data_format; + sev.xclient.serial = CurrentTime; + memcpy(&sev.xclient.data, &event->client.data, sizeof(sev.xclient.data)); + sev.xclient.message_type = event->client.message_type; + + /* OK, we're all set, now let's find some windows to send this to */ + if(XQueryTree(gdk_display, gdk_root_window, &ret_root, &ret_parent, + &ret_children, &ret_nchildren) != True) + return; + + /* foreach true child window of the root window, send an event to it */ + for(i = 0; i < ret_nchildren; i++) { + curwin = gdk_get_client_window(gdk_display, ret_children[i]); + sev.xclient.window = curwin; + XSendEvent(gdk_display, curwin, False, NoEventMask, &sev); + } + + XFree(ret_children); +} diff --git a/gdk/x11/gdkpixmap-x11.c b/gdk/x11/gdkpixmap-x11.c new file mode 100644 index 000000000..d2d96b6da --- /dev/null +++ b/gdk/x11/gdkpixmap-x11.c @@ -0,0 +1,657 @@ +/* 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 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include "../config.h" +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <X11/Xlib.h> + +#include "gdk.h" +#include "gdkprivate.h" + +typedef struct +{ + gchar *color_string; + GdkColor color; + gint transparent; +} _GdkPixmapColor; + +GdkPixmap* +gdk_pixmap_new (GdkWindow *window, + gint width, + gint height, + gint depth) +{ + GdkPixmap *pixmap; + GdkWindowPrivate *private; + GdkWindowPrivate *window_private; + + if (!window) + window = (GdkWindow*) &gdk_root_parent; + + if (depth == -1) + gdk_window_get_geometry (window, NULL, NULL, NULL, NULL, &depth); + + private = g_new (GdkWindowPrivate, 1); + pixmap = (GdkPixmap*) private; + + window_private = (GdkWindowPrivate*) window; + + private->xdisplay = window_private->xdisplay; + private->window_type = GDK_WINDOW_PIXMAP; + private->xwindow = XCreatePixmap (private->xdisplay, window_private->xwindow, + width, height, depth); + private->parent = NULL; + private->x = 0; + private->y = 0; + private->width = width; + private->height = height; + private->resize_count = 0; + private->ref_count = 1; + private->destroyed = 0; + + gdk_xid_table_insert (&private->xwindow, pixmap); + + return pixmap; +} + +GdkPixmap * +gdk_bitmap_create_from_data (GdkWindow *window, + gchar *data, + gint width, + gint height) +{ + GdkPixmap *pixmap; + GdkWindowPrivate *private; + GdkWindowPrivate *window_private; + + g_return_val_if_fail (data != NULL, NULL); + + if (!window) + window = (GdkWindow*) &gdk_root_parent; + + private = g_new (GdkWindowPrivate, 1); + pixmap = (GdkPixmap*) private; + + window_private = (GdkWindowPrivate*) window; + + private->parent = NULL; + private->xdisplay = window_private->xdisplay; + private->window_type = GDK_WINDOW_PIXMAP; + private->x = 0; + private->y = 0; + private->width = width; + private->height = height; + private->resize_count = 0; + private->ref_count = 1; + private->destroyed = FALSE; + + private->xwindow = XCreateBitmapFromData (private->xdisplay, + window_private->xwindow, + data, width, height); + + gdk_xid_table_insert (&private->xwindow, pixmap); + + return pixmap; +} + +GdkPixmap* +gdk_pixmap_create_from_data (GdkWindow *window, + gchar *data, + gint width, + gint height, + gint depth, + GdkColor *fg, + GdkColor *bg) +{ + GdkPixmap *pixmap; + GdkWindowPrivate *private; + GdkWindowPrivate *window_private; + + g_return_val_if_fail (data != NULL, NULL); + g_return_val_if_fail (fg != NULL, NULL); + g_return_val_if_fail (bg != NULL, NULL); + + if (!window) + window = (GdkWindow*) &gdk_root_parent; + + if (depth == -1) + gdk_window_get_geometry (window, NULL, NULL, NULL, NULL, &depth); + + private = g_new (GdkWindowPrivate, 1); + pixmap = (GdkPixmap*) private; + + window_private = (GdkWindowPrivate*) window; + + private->parent = NULL; + private->xdisplay = window_private->xdisplay; + private->window_type = GDK_WINDOW_PIXMAP; + private->x = 0; + private->y = 0; + private->width = width; + private->height = height; + private->resize_count = 0; + private->ref_count = 1; + private->destroyed = FALSE; + + private->xwindow = XCreatePixmapFromBitmapData (private->xdisplay, + window_private->xwindow, + data, width, height, + fg->pixel, bg->pixel, depth); + + gdk_xid_table_insert (&private->xwindow, pixmap); + + return pixmap; +} + +gint +gdk_pixmap_seek_string (FILE *infile, + const gchar *str, + gint skip_comments) +{ + char instr[1024]; + + while (!feof (infile)) + { + fscanf (infile, "%s", instr); + if (skip_comments == TRUE && strcmp (instr, "/*") == 0) + { + fscanf (infile, "%s", instr); + while (!feof (infile) && strcmp (instr, "*/") != 0) + fscanf (infile, "%s", instr); + fscanf(infile, "%s", instr); + } + if (strcmp (instr, str)==0) + return TRUE; + } + + return FALSE; +} + +gint +gdk_pixmap_seek_char (FILE *infile, + gchar c) +{ + gchar b, oldb; + + while (!feof (infile)) + { + fscanf(infile, "%c", &b); + if (c != b && b == '/') + { + fscanf (infile, "%c", &b); + if (b == '*') + { + oldb = b; + while (!feof (infile) && !(oldb == '*' && b == '/')) + { + oldb = b; + fscanf (infile, "%c", &b); + } + fscanf (infile, "%c", &b); + } + } + if (c == b) + return TRUE; + } + + return FALSE; +} + +gint +gdk_pixmap_read_string (FILE *infile, + gchar **buffer, + int *buffer_size) +{ + gchar c; + gint cnt = 0; + + if ((*buffer) == NULL) + { + (*buffer_size) = 10 * sizeof (gchar); + (*buffer) = (gchar *) malloc (*buffer_size); + } + + do + fscanf (infile, "%c", &c); + while (!feof (infile) && c != '"'); + + if (c != '"') + return FALSE; + + while (!feof (infile)) + { + fscanf (infile, "%c", &c); + + if (cnt == (*buffer_size)) + { + (*buffer_size) *= 2; + (*buffer) = (gchar *) realloc ((*buffer), *buffer_size); + } + + if (c != '"') + (*buffer)[cnt++] = c; + else + { + (*buffer)[cnt++] = 0; + return TRUE; + } + } + + return FALSE; +} + +gchar* +gdk_pixmap_skip_whitespaces (gchar *buffer) +{ + gint32 index = 0; + + while (buffer[index] != 0 && (buffer[index] == 0x20 || buffer[index] == 0x09)) + index++; + + return &buffer[index]; +} + +gchar* +gdk_pixmap_skip_string (gchar *buffer) +{ + gint32 index = 0; + + while (buffer[index] != 0 && buffer[index] != 0x20 && buffer[index] != 0x09) + index++; + + return &buffer[index]; +} + +gchar* +gdk_pixmap_extract_color (gchar *buffer) +{ + gint counter, finished = FALSE, numnames; + gchar *ptr = NULL, ch, temp[128]; + gchar color[128], *retcol; + + counter = 0; + while (ptr == NULL) + { + if (buffer[counter] == 'c') + { + ch = buffer[counter + 1]; + if (ch == 0x20 || ch == 0x09) + ptr = &buffer[counter + 1]; + } + else if (buffer[counter] == 0) + return NULL; + + counter++; + } + + if (ptr == NULL) + return NULL; + + ptr = gdk_pixmap_skip_whitespaces (ptr); + + if (ptr[0] == 0) + return NULL; + else if (ptr[0] == '#') + { + retcol = g_new(gchar, strlen (ptr) + 1); + strcpy (retcol, ptr); + return retcol; + } + + color[0] = 0; + numnames = 0; + + while (finished == FALSE) + { + sscanf (ptr, "%s", temp); + + if ((gint)ptr[0] == 0 || strcmp ("s", temp) == 0 || strcmp ("m", temp) == 0 || + strcmp ("g", temp) == 0 || strcmp ("g4", temp) == 0) + finished = TRUE; + else + { + if (numnames > 0) + strcat (color, " "); + strcat (color, temp); + ptr = gdk_pixmap_skip_string (ptr); + ptr = gdk_pixmap_skip_whitespaces (ptr); + numnames++; + } + } + + retcol = g_new(gchar, strlen (color) + 1); + strcpy (retcol, color); + return retcol; +} + + +GdkPixmap* +gdk_pixmap_create_from_xpm (GdkWindow *window, + GdkBitmap **mask, + GdkColor *transparent_color, + const gchar *filename) +{ + FILE *infile = NULL; + GdkPixmap *pixmap = NULL; + GdkImage *image = NULL; + GdkColormap *colormap; + GdkVisual *visual; + GdkGC *gc; + GdkColor tmp_color; + gint width, height, num_cols, cpp, cnt, n, ns, xcnt, ycnt; + gchar *buffer = NULL, *color_name = NULL, pixel_str[32]; + guint buffer_size = 0; + _GdkPixmapColor *colors = NULL, *color = NULL; + gulong index; + + if (!window) + window = (GdkWindow*) &gdk_root_parent; + + infile = fopen (filename, "rb"); + if (infile != NULL) + { + if (gdk_pixmap_seek_string (infile, "XPM", FALSE) == TRUE) + { + if (gdk_pixmap_seek_char (infile,'{') == TRUE) + { + gdk_pixmap_seek_char (infile, '"'); + fseek (infile, -1, SEEK_CUR); + gdk_pixmap_read_string (infile, &buffer, &buffer_size); + + sscanf (buffer,"%d %d %d %d", &width, &height, &num_cols, &cpp); + + colors = g_new(_GdkPixmapColor, num_cols); + + colormap = gdk_window_get_colormap (window); + visual = gdk_window_get_visual (window); + + if (transparent_color == NULL) + { + gdk_color_white (colormap, &tmp_color); + transparent_color = &tmp_color; + } + + for (cnt = 0; cnt < num_cols; cnt++) + { + gdk_pixmap_seek_char (infile, '"'); + fseek (infile, -1, SEEK_CUR); + gdk_pixmap_read_string (infile, &buffer, &buffer_size); + + colors[cnt].color_string = g_new(gchar, cpp + 1); + for (n = 0; n < cpp; n++) + colors[cnt].color_string[n] = buffer[n]; + colors[cnt].color_string[n] = 0; + colors[cnt].transparent = FALSE; + + if (color_name != NULL) + g_free (color_name); + + color_name = gdk_pixmap_extract_color (&buffer[cpp]); + + if (color_name != NULL) + { + if (gdk_color_parse (color_name, &colors[cnt].color) == FALSE) + { + colors[cnt].color = *transparent_color; + colors[cnt].transparent = TRUE; + } + } + else + { + colors[cnt].color = *transparent_color; + colors[cnt].transparent = TRUE; + } + + gdk_color_alloc (colormap, &colors[cnt].color); + } + + index = 0; + image = gdk_image_new (GDK_IMAGE_FASTEST, visual, width, height); + + gc = NULL; + if (mask) + { + *mask = gdk_pixmap_new (window, width, height, 1); + gc = gdk_gc_new (*mask); + + gdk_color_black (colormap, &tmp_color); + gdk_gc_set_foreground (gc, &tmp_color); + gdk_draw_rectangle (*mask, gc, TRUE, 0, 0, -1, -1); + + gdk_color_white (colormap, &tmp_color); + gdk_gc_set_foreground (gc, &tmp_color); + } + + for (ycnt = 0; ycnt < height; ycnt++) + { + gdk_pixmap_read_string (infile, &buffer, &buffer_size); + + for (n = 0, cnt = 0, xcnt = 0; n < (width * cpp); n += cpp, xcnt++) + { + strncpy (pixel_str, &buffer[n], cpp); + pixel_str[cpp] = 0; + color = NULL; + ns = 0; + + while (color == NULL) + { + if (strcmp (pixel_str, colors[ns].color_string) == 0) + color = &colors[ns]; + else + ns++; + } + + gdk_image_put_pixel (image, xcnt, ycnt, color->color.pixel); + + if (mask && color->transparent) + { + if (cnt < xcnt) + gdk_draw_line (*mask, gc, cnt, ycnt, xcnt - 1, ycnt); + cnt = xcnt + 1; + } + } + + if (mask && (cnt < xcnt)) + gdk_draw_line (*mask, gc, cnt, ycnt, xcnt - 1, ycnt); + } + + if (mask) + gdk_gc_destroy (gc); + + pixmap = gdk_pixmap_new (window, width, height, visual->depth); + + gc = gdk_gc_new (pixmap); + gdk_gc_set_foreground (gc, transparent_color); + gdk_draw_image (pixmap, gc, image, 0, 0, 0, 0, image->width, image->height); + gdk_gc_destroy (gc); + gdk_image_destroy (image); + } + } + + fclose (infile); + free (buffer); + + if (colors != NULL) + { + for (cnt = 0; cnt < num_cols; cnt++) + g_free (colors[cnt].color_string); + g_free (colors); + } + } + + return pixmap; +} + +GdkPixmap* +gdk_pixmap_create_from_xpm_d (GdkWindow *window, + GdkBitmap **mask, + GdkColor *transparent_color, + gchar **data) +{ + GdkPixmap *pixmap = NULL; + GdkImage *image = NULL; + GdkColormap *colormap; + GdkVisual *visual; + GdkGC *gc; + GdkColor tmp_color; + gint width, height, num_cols, cpp, cnt, n, ns, xcnt, ycnt, i; + gchar *buffer, *color_name = NULL, pixel_str[32]; + _GdkPixmapColor *colors = NULL, *color = NULL; + gulong index; + + if (!window) + window = (GdkWindow*) &gdk_root_parent; + + i = 0; + buffer = data[i++]; + sscanf (buffer,"%d %d %d %d", &width, &height, &num_cols, &cpp); + + colors = g_new(_GdkPixmapColor, num_cols); + + colormap = gdk_window_get_colormap (window); + visual = gdk_window_get_visual (window); + + if (transparent_color == NULL) + { + gdk_color_white (colormap, &tmp_color); + transparent_color = &tmp_color; + } + + for (cnt = 0; cnt < num_cols; cnt++) + { + buffer = data[i++]; + + colors[cnt].color_string = g_new(gchar, cpp + 1); + for (n = 0; n < cpp; n++) + colors[cnt].color_string[n] = buffer[n]; + colors[cnt].color_string[n] = 0; + colors[cnt].transparent = FALSE; + + if (color_name != NULL) + g_free (color_name); + + color_name = gdk_pixmap_extract_color (&buffer[cpp]); + + if (color_name != NULL) + { + if (gdk_color_parse (color_name, &colors[cnt].color) == FALSE) + { + colors[cnt].color = *transparent_color; + colors[cnt].transparent = TRUE; + } + } + else + { + colors[cnt].color = *transparent_color; + colors[cnt].transparent = TRUE; + } + + gdk_color_alloc (colormap, &colors[cnt].color); + } + + index = 0; + image = gdk_image_new (GDK_IMAGE_FASTEST, visual, width, height); + + gc = NULL; + if (mask) + { + *mask = gdk_pixmap_new (window, width, height, 1); + gc = gdk_gc_new (*mask); + + gdk_color_black (colormap, &tmp_color); + gdk_gc_set_foreground (gc, &tmp_color); + gdk_draw_rectangle (*mask, gc, TRUE, 0, 0, -1, -1); + + gdk_color_white (colormap, &tmp_color); + gdk_gc_set_foreground (gc, &tmp_color); + } + + for (ycnt = 0; ycnt < height; ycnt++) + { + buffer = data[i++]; + + for (n = 0, cnt = 0, xcnt = 0; n < (width * cpp); n += cpp, xcnt++) + { + strncpy (pixel_str, &buffer[n], cpp); + pixel_str[cpp] = 0; + color = NULL; + ns = 0; + + while (color == NULL) + { + if (strcmp (pixel_str, colors[ns].color_string) == 0) + color = &colors[ns]; + else + ns++; + } + + gdk_image_put_pixel (image, xcnt, ycnt, color->color.pixel); + + if (mask && color->transparent) + { + if (cnt < xcnt) + gdk_draw_line (*mask, gc, cnt, ycnt, xcnt - 1, ycnt); + cnt = xcnt + 1; + } + } + + if (mask && (cnt < xcnt)) + gdk_draw_line (*mask, gc, cnt, ycnt, xcnt - 1, ycnt); + } + + if (mask) + gdk_gc_destroy (gc); + + pixmap = gdk_pixmap_new (window, width, height, visual->depth); + + gc = gdk_gc_new (pixmap); + gdk_gc_set_foreground (gc, transparent_color); + gdk_draw_image (pixmap, gc, image, 0, 0, 0, 0, image->width, image->height); + gdk_gc_destroy (gc); + gdk_image_destroy (image); + + if (colors != NULL) + { + for (cnt = 0; cnt < num_cols; cnt++) + g_free (colors[cnt].color_string); + g_free (colors); + } + + return pixmap; +} + +void +gdk_pixmap_destroy (GdkPixmap *pixmap) +{ + GdkWindowPrivate *private; + + g_return_if_fail (pixmap != NULL); + + private = (GdkPixmapPrivate*) pixmap; + if (private->ref_count <= 0) + { + XFreePixmap (private->xdisplay, private->xwindow); + gdk_xid_table_remove (private->xwindow); + g_free (pixmap); + } + else + { + private->ref_count -= 1; + } +} diff --git a/gdk/x11/gdkproperty-x11.c b/gdk/x11/gdkproperty-x11.c new file mode 100644 index 000000000..35d8a50cf --- /dev/null +++ b/gdk/x11/gdkproperty-x11.c @@ -0,0 +1,194 @@ +/* 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 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include <X11/Xlib.h> +#include <X11/Xatom.h> +#include <string.h> +#include "gdk.h" +#include "gdkprivate.h" + + +GdkAtom +gdk_atom_intern (const gchar *atom_name, + gint only_if_exists) +{ + return XInternAtom (gdk_display, atom_name, only_if_exists); +} + +gchar * +gdk_atom_name (GdkAtom atom) +{ + gchar *t; + gchar *name; + + /* If this atom doesn't exist, we'll die with an X error unless + we take precautions */ + + gdk_error_warnings = 0; + t = XGetAtomName (gdk_display, atom); + gdk_error_warnings = 1; + + if (gdk_error_code == -1) + { + return NULL; + } + else + { + name = g_strdup (t); + XFree (t); + + return name; + } +} + +gint +gdk_property_get (GdkWindow *window, + GdkAtom property, + GdkAtom type, + gulong offset, + gulong length, + gint pdelete, + GdkAtom *actual_property_type, + gint *actual_format_type, + gint *actual_length, + guchar **data) +{ + GdkWindowPrivate *private; + Display *xdisplay; + Window xwindow; + Atom ret_prop_type; + gint ret_format; + gulong ret_nitems; + gulong ret_bytes_after; + gulong ret_length; + guchar *ret_data; + + if (window) + { + private = (GdkWindowPrivate*) window; + xdisplay = private->xdisplay; + xwindow = private->xwindow; + } + else + { + xdisplay = gdk_display; + xwindow = gdk_root_window; + } + + XGetWindowProperty (xdisplay, xwindow, property, + offset, (length + 3) / 4, pdelete, + type, &ret_prop_type, &ret_format, + &ret_nitems, &ret_bytes_after, + &ret_data); + + if ((ret_prop_type == None) && (ret_format == 0)) + return FALSE; + + if (actual_property_type) + *actual_property_type = ret_prop_type; + if (actual_format_type) + *actual_format_type = ret_format; + + if (ret_prop_type != property) + { + XFree (ret_data); + return FALSE; + } + + /* FIXME: ignoring bytes_after could have very bad effects */ + + if (data) + { + switch (ret_format) + { + case 8: + ret_length = ret_nitems; + break; + case 16: + ret_length = 2 * ret_nitems; + break; + case 32: + ret_length = 4 * ret_nitems; + break; + default: + g_warning ("unknown property return format: %d", ret_format); + XFree (ret_data); + return FALSE; + } + + *data = g_new (guchar, ret_length); + memcpy (*data, ret_data, ret_length); + if (actual_length) + *actual_length = ret_length; + } + + XFree (ret_data); + + return TRUE; +} + +void +gdk_property_change (GdkWindow *window, + GdkAtom property, + GdkAtom type, + gint format, + GdkPropMode mode, + guchar *data, + gint nelements) +{ + GdkWindowPrivate *private; + Display *xdisplay; + Window xwindow; + + if (window) + { + private = (GdkWindowPrivate*) window; + xdisplay = private->xdisplay; + xwindow = private->xwindow; + } + else + { + xdisplay = gdk_display; + xwindow = gdk_root_window; + } + + XChangeProperty (xdisplay, xwindow, property, type, + format, mode, data, nelements); +} + +void +gdk_property_delete (GdkWindow *window, + GdkAtom property) +{ + GdkWindowPrivate *private; + Display *xdisplay; + Window xwindow; + + if (window) + { + private = (GdkWindowPrivate*) window; + xdisplay = private->xdisplay; + xwindow = private->xwindow; + } + else + { + xdisplay = gdk_display; + xwindow = gdk_root_window; + } + + XDeleteProperty (xdisplay, xwindow, property); +} diff --git a/gdk/x11/gdkselection-x11.c b/gdk/x11/gdkselection-x11.c new file mode 100644 index 000000000..6bd425110 --- /dev/null +++ b/gdk/x11/gdkselection-x11.c @@ -0,0 +1,168 @@ +/* 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 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include <X11/Xlib.h> +#include <X11/Xatom.h> +#include <string.h> +#include "gdk.h" +#include "gdkprivate.h" + + +gint +gdk_selection_owner_set (GdkWindow *owner, + GdkAtom selection, + guint32 time, + gint send_event) +{ + GdkWindowPrivate *private; + Display *xdisplay; + Window xwindow; + + if (owner) + { + private = (GdkWindowPrivate*) owner; + xdisplay = private->xdisplay; + xwindow = private->xwindow; + } + else + { + xdisplay = gdk_display; + xwindow = None; + } + + XSetSelectionOwner (xdisplay, selection, xwindow, time); + + return (XGetSelectionOwner (xdisplay, selection) == xwindow); +} + +GdkWindow* +gdk_selection_owner_get (GdkAtom selection) +{ + Window xwindow; + + xwindow = XGetSelectionOwner (gdk_display, selection); + if (xwindow == None) + return NULL; + + return gdk_window_lookup (xwindow); +} + +void +gdk_selection_convert (GdkWindow *requestor, + GdkAtom selection, + GdkAtom target, + guint32 time) +{ + GdkWindowPrivate *private; + + g_return_if_fail (requestor != NULL); + + private = (GdkWindowPrivate*) requestor; + + XConvertSelection (private->xdisplay, selection, target, + gdk_selection_property, private->xwindow, time); +} + +gint +gdk_selection_property_get (GdkWindow *requestor, + guchar **data, + GdkAtom *ret_type, + gint *ret_format) +{ + GdkWindowPrivate *private; + gulong nitems; + gulong nbytes; + gulong length; + GdkAtom prop_type; + gint prop_format; + guchar *t; + + g_return_val_if_fail (requestor != NULL, 0); + + /* If retrieved chunks are typically small, (and the ICCM says the + should be) it would be a win to try first with a buffer of + moderate length, to avoid two round trips to the server */ + + private = (GdkWindowPrivate*) requestor; + + XGetWindowProperty (private->xdisplay, private->xwindow, + gdk_selection_property, 0, 0, False, + AnyPropertyType, &prop_type, &prop_format, + &nitems, &nbytes, &t); + + if (ret_type) + *ret_type = prop_type; + if (ret_format) + *ret_format = prop_format; + + if (prop_type == None) + { + *data = NULL; + return 0; + } + + XFree (t); + + /* Add on an extra byte to handle null termination. X guarantees + that t will be 1 longer than nbytes and null terminated */ + length = nbytes + 1; + + /* We can't delete the selection here, because it might be the INCR + protocol, in which case the client has to make sure they'll be + notified of PropertyChange events _before_ the property is deleted. + Otherwise there's no guarantee we'll win the race ... */ + XGetWindowProperty (private->xdisplay, private->xwindow, + gdk_selection_property, 0, (nbytes + 3) / 4, False, + AnyPropertyType, &prop_type, &prop_format, + &nitems, &nbytes, &t); + + if (prop_type != None) + { + *data = g_new (guchar, length); + memcpy (*data, t, length); + XFree (t); + return length-1; + } + else + { + *data = NULL; + return 0; + } +} + + +void +gdk_selection_send_notify (guint32 requestor, + GdkAtom selection, + GdkAtom target, + GdkAtom property, + guint32 time) +{ + XSelectionEvent xevent; + + xevent.type = SelectionNotify; + xevent.serial = 0; + xevent.send_event = True; + xevent.display = gdk_display; + xevent.requestor = requestor; + xevent.selection = selection; + xevent.target = target; + xevent.property = property; + xevent.time = time; + + XSendEvent (gdk_display, requestor, False, NoEventMask, (XEvent*) &xevent); +} diff --git a/gdk/x11/gdkvisual-x11.c b/gdk/x11/gdkvisual-x11.c new file mode 100644 index 000000000..22acee6f1 --- /dev/null +++ b/gdk/x11/gdkvisual-x11.c @@ -0,0 +1,431 @@ +/* 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 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include <X11/Xlib.h> +#include <X11/Xutil.h> +#include "gdk.h" +#include "gdkprivate.h" + + +static void gdk_visual_add (GdkVisual *visual); +static void gdk_visual_decompose_mask (gulong mask, + gint *shift, + gint *prec); +static guint gdk_visual_hash (Visual *key); +static gint gdk_visual_compare (Visual *a, + Visual *b); + + +static GdkVisualPrivate *system_visual; +static GdkVisualPrivate *visuals; +static gint nvisuals; + +static gint available_depths[4]; +static gint navailable_depths; + +static GdkVisualType available_types[6]; +static gint navailable_types; + +static char* visual_names[] = +{ + "static gray", + "grayscale", + "static color", + "pseudo color", + "true color", + "direct color", +}; + +static GHashTable *visual_hash = NULL; + +void +gdk_visual_init () +{ + static gint possible_depths[5] = { 32, 24, 16, 15, 8 }; + static GdkVisualType possible_types[6] = + { + GDK_VISUAL_DIRECT_COLOR, + GDK_VISUAL_TRUE_COLOR, + GDK_VISUAL_PSEUDO_COLOR, + GDK_VISUAL_STATIC_COLOR, + GDK_VISUAL_GRAYSCALE, + GDK_VISUAL_STATIC_GRAY + }; + + static gint npossible_depths = 5; + static gint npossible_types = 6; + + XVisualInfo *visual_list; + XVisualInfo visual_template; + GdkVisualPrivate temp_visual; + Visual *default_xvisual; + int nxvisuals; + int i, j; + + visual_template.screen = gdk_screen; + visual_list = XGetVisualInfo (gdk_display, VisualScreenMask, &visual_template, &nxvisuals); + visuals = g_new (GdkVisualPrivate, nxvisuals); + + default_xvisual = DefaultVisual (gdk_display, gdk_screen); + + nvisuals = 0; + for (i = 0; i < nxvisuals; i++) + { + if (visual_list[i].depth >= 8) + { +#ifdef __cplusplus + switch (visual_list[i].c_class) +#else /* __cplusplus */ + switch (visual_list[i].class) +#endif /* __cplusplus */ + { + case StaticGray: + visuals[nvisuals].visual.type = GDK_VISUAL_STATIC_GRAY; + break; + case GrayScale: + visuals[nvisuals].visual.type = GDK_VISUAL_GRAYSCALE; + break; + case StaticColor: + visuals[nvisuals].visual.type = GDK_VISUAL_STATIC_COLOR; + break; + case PseudoColor: + visuals[nvisuals].visual.type = GDK_VISUAL_PSEUDO_COLOR; + break; + case TrueColor: + visuals[nvisuals].visual.type = GDK_VISUAL_TRUE_COLOR; + break; + case DirectColor: + visuals[nvisuals].visual.type = GDK_VISUAL_DIRECT_COLOR; + break; + } + + visuals[nvisuals].visual.depth = visual_list[i].depth; + visuals[nvisuals].visual.byte_order = + (ImageByteOrder(gdk_display) == LSBFirst) ? + GDK_LSB_FIRST : GDK_MSB_FIRST; + visuals[nvisuals].visual.red_mask = visual_list[i].red_mask; + visuals[nvisuals].visual.green_mask = visual_list[i].green_mask; + visuals[nvisuals].visual.blue_mask = visual_list[i].blue_mask; + visuals[nvisuals].visual.colormap_size = visual_list[i].colormap_size; + visuals[nvisuals].visual.bits_per_rgb = visual_list[i].bits_per_rgb; + visuals[nvisuals].xvisual = visual_list[i].visual; + + if ((visuals[nvisuals].visual.type == GDK_VISUAL_TRUE_COLOR) || + (visuals[nvisuals].visual.type == GDK_VISUAL_DIRECT_COLOR)) + { + gdk_visual_decompose_mask (visuals[nvisuals].visual.red_mask, + &visuals[nvisuals].visual.red_shift, + &visuals[nvisuals].visual.red_prec); + + gdk_visual_decompose_mask (visuals[nvisuals].visual.green_mask, + &visuals[nvisuals].visual.green_shift, + &visuals[nvisuals].visual.green_prec); + + gdk_visual_decompose_mask (visuals[nvisuals].visual.blue_mask, + &visuals[nvisuals].visual.blue_shift, + &visuals[nvisuals].visual.blue_prec); + } + else + { + visuals[nvisuals].visual.red_mask = 0; + visuals[nvisuals].visual.red_shift = 0; + visuals[nvisuals].visual.red_prec = 0; + + visuals[nvisuals].visual.green_mask = 0; + visuals[nvisuals].visual.green_shift = 0; + visuals[nvisuals].visual.green_prec = 0; + + visuals[nvisuals].visual.blue_mask = 0; + visuals[nvisuals].visual.blue_shift = 0; + visuals[nvisuals].visual.blue_prec = 0; + } + + nvisuals += 1; + } + } + + XFree (visual_list); + + for (i = 0; i < nvisuals; i++) + { + for (j = i+1; j < nvisuals; j++) + { + if (visuals[j].visual.depth >= visuals[i].visual.depth) + { + if ((visuals[j].visual.depth == 8) && (visuals[i].visual.depth == 8)) + { + if (visuals[j].visual.type == GDK_VISUAL_PSEUDO_COLOR) + { + temp_visual = visuals[j]; + visuals[j] = visuals[i]; + visuals[i] = temp_visual; + } + else if ((visuals[i].visual.type != GDK_VISUAL_PSEUDO_COLOR) && + visuals[j].visual.type > visuals[i].visual.type) + { + temp_visual = visuals[j]; + visuals[j] = visuals[i]; + visuals[i] = temp_visual; + } + } + else if ((visuals[j].visual.depth > visuals[i].visual.depth) || + ((visuals[j].visual.depth == visuals[i].visual.depth) && + (visuals[j].visual.type > visuals[i].visual.type))) + { + temp_visual = visuals[j]; + visuals[j] = visuals[i]; + visuals[i] = temp_visual; + } + } + } + } + + for (i = 0; i < nvisuals; i++) + if (default_xvisual->visualid == visuals[i].xvisual->visualid) + { + system_visual = &visuals[i]; + break; + } + + if (gdk_debug_level >= 1) + for (i = 0; i < nvisuals; i++) + g_print ("visual: %s: %d\n", + visual_names[visuals[i].visual.type], + visuals[i].visual.depth); + + navailable_depths = 0; + for (i = 0; i < npossible_depths; i++) + { + for (j = 0; j < nvisuals; j++) + { + if (visuals[j].visual.depth == possible_depths[i]) + { + available_depths[navailable_depths++] = visuals[j].visual.depth; + break; + } + } + } + + if (navailable_depths == 0) + g_error ("unable to find a usable depth"); + + navailable_types = 0; + for (i = 0; i < npossible_types; i++) + { + for (j = 0; j < nvisuals; j++) + { + if (visuals[j].visual.type == possible_types[i]) + { + available_types[navailable_types++] = visuals[j].visual.type; + break; + } + } + } + + for (i = 0; i < nvisuals; i++) + gdk_visual_add ((GdkVisual*) &visuals[i]); + + if (npossible_types == 0) + g_error ("unable to find a usable visual type"); +} + +GdkVisual* +gdk_visual_ref (GdkVisual *visual) +{ + return visual; +} + +void +gdk_visual_unref (GdkVisual *visual) +{ + return; +} + +gint +gdk_visual_get_best_depth () +{ + return available_depths[0]; +} + +GdkVisualType +gdk_visual_get_best_type () +{ + return available_types[0]; +} + +GdkVisual* +gdk_visual_get_system () +{ + return ((GdkVisual*) system_visual); +} + +GdkVisual* +gdk_visual_get_best () +{ + return ((GdkVisual*) &(visuals[0])); +} + +GdkVisual* +gdk_visual_get_best_with_depth (gint depth) +{ + GdkVisual *return_val; + int i; + + return_val = NULL; + for (i = 0; i < nvisuals; i++) + if (depth == visuals[i].visual.depth) + { + return_val = (GdkVisual*) &(visuals[i]); + break; + } + + return return_val; +} + +GdkVisual* +gdk_visual_get_best_with_type (GdkVisualType visual_type) +{ + GdkVisual *return_val; + int i; + + return_val = NULL; + for (i = 0; i < nvisuals; i++) + if (visual_type == visuals[i].visual.type) + { + return_val = (GdkVisual*) &(visuals[i]); + break; + } + + return return_val; +} + +GdkVisual* +gdk_visual_get_best_with_both (gint depth, + GdkVisualType visual_type) +{ + GdkVisual *return_val; + int i; + + return_val = NULL; + for (i = 0; i < nvisuals; i++) + if ((depth == visuals[i].visual.depth) && + (visual_type == visuals[i].visual.type)) + { + return_val = (GdkVisual*) &(visuals[i]); + break; + } + + return return_val; +} + +void +gdk_query_depths (gint **depths, + gint *count) +{ + *count = navailable_depths; + *depths = available_depths; +} + +void +gdk_query_visual_types (GdkVisualType **visual_types, + gint *count) +{ + *count = navailable_types; + *visual_types = available_types; +} + +void +gdk_query_visuals (GdkVisual **visual_return, + gint *count) +{ + *count = nvisuals; + *visual_return = (GdkVisual*) visuals; +} + + +GdkVisual* +gdk_visual_lookup (Visual *xvisual) +{ + GdkVisual *visual; + + if (!visual_hash) + return NULL; + + visual = g_hash_table_lookup (visual_hash, xvisual); + return visual; +} + +GdkVisual* +gdkx_visual_get (VisualID xvisualid) +{ + int i; + + for (i = 0; i < nvisuals; i++) + if (xvisualid == visuals[i].xvisual->visualid) + return (GdkVisual*) &visuals[i]; + + return NULL; +} + + +static void +gdk_visual_add (GdkVisual *visual) +{ + GdkVisualPrivate *private; + + if (!visual_hash) + visual_hash = g_hash_table_new ((GHashFunc) gdk_visual_hash, + (GCompareFunc) gdk_visual_compare); + + private = (GdkVisualPrivate*) visual; + + g_hash_table_insert (visual_hash, private->xvisual, visual); +} + +static void +gdk_visual_decompose_mask (gulong mask, + gint *shift, + gint *prec) +{ + *shift = 0; + *prec = 0; + + while (!(mask & 0x1)) + { + (*shift)++; + mask >>= 1; + } + + while (mask & 0x1) + { + (*prec)++; + mask >>= 1; + } +} + +static guint +gdk_visual_hash (Visual *key) +{ + return key->visualid; +} + +static gint +gdk_visual_compare (Visual *a, + Visual *b) +{ + return (a->visualid == b->visualid); +} diff --git a/gdk/x11/gdkwindow-x11.c b/gdk/x11/gdkwindow-x11.c new file mode 100644 index 000000000..aef1367d9 --- /dev/null +++ b/gdk/x11/gdkwindow-x11.c @@ -0,0 +1,1358 @@ +/* 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 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include <X11/Xlib.h> +#include <X11/Xutil.h> +#include <X11/Xatom.h> +#include <X11/extensions/shape.h> +#include <netinet/in.h> +#include "gdk.h" +#include "gdkinput.h" +#include "gdkprivate.h" +#include <stdlib.h> + +int nevent_masks = 16; +int event_mask_table[18] = +{ + ExposureMask, + PointerMotionMask, + PointerMotionHintMask, + ButtonMotionMask, + Button1MotionMask, + Button2MotionMask, + Button3MotionMask, + ButtonPressMask | OwnerGrabButtonMask, + ButtonReleaseMask | OwnerGrabButtonMask, + KeyPressMask, + KeyReleaseMask, + EnterWindowMask, + LeaveWindowMask, + FocusChangeMask, + StructureNotifyMask, + PropertyChangeMask, + 0, /* PROXIMITY_IN */ + 0 /* PROXIMTY_OUT */ +}; + + +void +gdk_window_init () +{ + XWindowAttributes xattributes; + unsigned int width; + unsigned int height; + unsigned int border_width; + unsigned int depth; + int x, y; + + XGetGeometry (gdk_display, gdk_root_window, &gdk_root_window, + &x, &y, &width, &height, &border_width, &depth); + XGetWindowAttributes (gdk_display, gdk_root_window, &xattributes); + + gdk_root_parent.xdisplay = gdk_display; + gdk_root_parent.xwindow = gdk_root_window; + gdk_root_parent.window_type = GDK_WINDOW_ROOT; + gdk_root_parent.window.user_data = NULL; +} + +GdkWindow* +gdk_window_new (GdkWindow *parent, + GdkWindowAttr *attributes, + gint attributes_mask) +{ + GdkWindow *window; + GdkWindowPrivate *private; + GdkWindowPrivate *parent_private; + GdkVisual *visual; + GdkColormap *colormap; + Display *parent_display; + Window xparent; + Visual *xvisual; + XSetWindowAttributes xattributes; + long xattributes_mask; + XSizeHints size_hints; + XWMHints wm_hints; + XTextProperty text_property; + XClassHint *class_hint; + int x, y, depth; + unsigned int class; + char *title; + int i; + + g_return_val_if_fail (attributes != NULL, NULL); + + if (!parent) + parent = (GdkWindow*) &gdk_root_parent; + + parent_private = (GdkWindowPrivate*) parent; + xparent = parent_private->xwindow; + parent_display = parent_private->xdisplay; + + private = g_new (GdkWindowPrivate, 1); + window = (GdkWindow*) private; + + private->parent = parent; + private->xdisplay = parent_display; + private->destroyed = FALSE; + private->resize_count = 0; + private->ref_count = 1; + xattributes_mask = 0; + + if (attributes_mask & GDK_WA_X) + x = attributes->x; + else + x = 0; + + if (attributes_mask & GDK_WA_Y) + y = attributes->y; + else + y = 0; + + private->x = x; + private->y = y; + private->width = (attributes->width > 1) ? (attributes->width) : (1); + private->height = (attributes->height > 1) ? (attributes->height) : (1); + private->window_type = attributes->window_type; + private->extension_events = FALSE; + private->dnd_drag_data_type = None; + private->dnd_drag_data_typesavail = + private->dnd_drop_data_typesavail = NULL; + private->dnd_drop_enabled = private->dnd_drag_enabled = + private->dnd_drag_accepted = private->dnd_drag_datashow = + private->dnd_drop_data_numtypesavail = + private->dnd_drag_data_numtypesavail = 0; + private->dnd_drag_eventmask = private->dnd_drag_savedeventmask = 0; + + window->user_data = NULL; + + if (attributes_mask & GDK_WA_VISUAL) + visual = attributes->visual; + else + visual = gdk_visual_get_system (); + xvisual = ((GdkVisualPrivate*) visual)->xvisual; + + xattributes.event_mask = StructureNotifyMask; + for (i = 0; i < nevent_masks; i++) + { + if (attributes->event_mask & (1 << (i + 1))) + xattributes.event_mask |= event_mask_table[i]; + } + + if (xattributes.event_mask) + xattributes_mask |= CWEventMask; + + if (attributes->wclass == GDK_INPUT_OUTPUT) + { + class = InputOutput; + depth = visual->depth; + + if (attributes_mask & GDK_WA_COLORMAP) + colormap = attributes->colormap; + else + colormap = gdk_colormap_get_system (); + + xattributes.background_pixel = BlackPixel (gdk_display, gdk_screen); + xattributes.border_pixel = BlackPixel (gdk_display, gdk_screen); + xattributes_mask |= CWBorderPixel | CWBackPixel; + + switch (private->window_type) + { + case GDK_WINDOW_TOPLEVEL: + xattributes.colormap = ((GdkColormapPrivate*) colormap)->xcolormap; + xattributes_mask |= CWColormap; + + xparent = gdk_root_window; + break; + + case GDK_WINDOW_CHILD: + xattributes.colormap = ((GdkColormapPrivate*) colormap)->xcolormap; + xattributes_mask |= CWColormap; + break; + + case GDK_WINDOW_DIALOG: + xattributes.colormap = ((GdkColormapPrivate*) colormap)->xcolormap; + xattributes_mask |= CWColormap; + + xparent = gdk_root_window; + break; + + case GDK_WINDOW_TEMP: + xattributes.colormap = ((GdkColormapPrivate*) colormap)->xcolormap; + xattributes_mask |= CWColormap; + + xparent = gdk_root_window; + + xattributes.save_under = True; + xattributes.override_redirect = True; + xattributes.cursor = None; + xattributes_mask |= CWSaveUnder | CWOverrideRedirect; + break; + case GDK_WINDOW_ROOT: + g_error ("cannot make windows of type GDK_WINDOW_ROOT"); + break; + case GDK_WINDOW_PIXMAP: + g_error ("cannot make windows of type GDK_WINDOW_PIXMAP (use gdk_pixmap_new)"); + break; + } + } + else + { + depth = 1; + class = InputOnly; + colormap = NULL; + } + + private->xwindow = XCreateWindow (private->xdisplay, xparent, + x, y, private->width, private->height, + 0, depth, class, xvisual, + xattributes_mask, &xattributes); + gdk_xid_table_insert (&private->xwindow, window); + + switch (private->window_type) + { + case GDK_WINDOW_DIALOG: + XSetTransientForHint (private->xdisplay, private->xwindow, xparent); + case GDK_WINDOW_TOPLEVEL: + case GDK_WINDOW_TEMP: + XSetWMProtocols (private->xdisplay, private->xwindow, gdk_wm_window_protocols, 2); + break; + case GDK_WINDOW_CHILD: + if ((attributes->wclass == GDK_INPUT_OUTPUT) && + (colormap != gdk_colormap_get_system ()) && + (colormap != gdk_window_get_colormap (gdk_window_get_toplevel (window)))) + { + g_print ("adding colormap window\n"); + gdk_window_add_colormap_windows (window); + } + break; + default: + break; + } + + size_hints.flags = PSize | PBaseSize; + size_hints.width = private->width; + size_hints.height = private->height; + size_hints.base_width = private->width; + size_hints.base_height = private->height; + + wm_hints.flags = InputHint | StateHint | WindowGroupHint; + wm_hints.window_group = gdk_leader_window; + wm_hints.input = True; + wm_hints.initial_state = NormalState; + + XSetWMNormalHints (private->xdisplay, private->xwindow, &size_hints); + XSetWMHints (private->xdisplay, private->xwindow, &wm_hints); + + if (attributes_mask & GDK_WA_TITLE) + title = attributes->title; + else + title = gdk_progname; + + if (XStringListToTextProperty (&title, 1, &text_property)) + { + XSetWMName (private->xdisplay, private->xwindow, &text_property); + XSetWMIconName (private->xdisplay, private->xwindow, &text_property); + XFree (text_property.value); + } + + if (attributes_mask & GDK_WA_WMCLASS) + { + class_hint = XAllocClassHint (); + class_hint->res_name = attributes->wmclass_name; + class_hint->res_class = attributes->wmclass_class; + XSetClassHint (private->xdisplay, private->xwindow, class_hint); + XFree (class_hint); + } + + gdk_window_set_cursor (window, ((attributes_mask & GDK_WA_CURSOR) ? + (attributes->cursor) : + NULL)); + + return window; +} + +GdkWindow * +gdk_window_foreign_new (guint32 anid) +{ + GdkWindow *window; + GdkWindowPrivate *private; + XWindowAttributes attrs; + + private = g_new (GdkWindowPrivate, 1); + window = (GdkWindow*) private; + + XGetWindowAttributes (gdk_display, anid, &attrs); + + private->parent = NULL; + private->xwindow = anid; + private->xdisplay = gdk_display; + private->x = attrs.x; + private->y = attrs.y; + private->width = attrs.width; + private->height = attrs.height; + private->resize_count = 0; + private->ref_count = 1; + if (anid == attrs.root) + private->window_type = GDK_WINDOW_ROOT; + else + private->window_type = GDK_WINDOW_TOPLEVEL; + /* the above is probably wrong, but it may not be worth the extra + X call to get it right */ + + private->destroyed = FALSE; + private->extension_events = 0; + + window->user_data = NULL; + + gdk_xid_table_insert (&private->xwindow, window); + + return window; +} + +void +gdk_window_destroy (GdkWindow *window) +{ + GdkWindowPrivate *private; + GdkWindowPrivate *temp_private; + GdkWindow *temp_window; + GList *children; + GList *tmp; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + if(private->dnd_drag_data_numtypesavail > 0) + { + free(private->dnd_drag_data_typesavail); + private->dnd_drag_data_typesavail = NULL; + } + if(private->dnd_drop_data_numtypesavail > 0) + { + free(private->dnd_drop_data_typesavail); + private->dnd_drop_data_typesavail = NULL; + } + + switch (private->window_type) + { + case GDK_WINDOW_TOPLEVEL: + case GDK_WINDOW_CHILD: + case GDK_WINDOW_DIALOG: + case GDK_WINDOW_TEMP: + if (private->ref_count >= 1) + private->ref_count -= 1; + + if (!private->destroyed || (private->destroyed == 2)) + { + children = gdk_window_get_children (window); + tmp = children; + + while (tmp) + { + temp_window = tmp->data; + tmp = tmp->next; + + temp_private = (GdkWindowPrivate*) temp_window; + if (temp_private && !temp_private->destroyed) + /* Removes some nice coredumps... /David */ + { + temp_private->destroyed = 2; + temp_private->ref_count += 1; + gdk_window_destroy (temp_window); + } + } + + g_list_free (children); + + if (!private->destroyed) + XDestroyWindow (private->xdisplay, private->xwindow); + private->destroyed = TRUE; + } + break; + + case GDK_WINDOW_ROOT: + g_error ("attempted to destroy root window"); + break; + + case GDK_WINDOW_PIXMAP: + g_warning ("called gdk_window_destroy on a pixmap (use gdk_pixmap_destroy)"); + gdk_pixmap_destroy (window); + break; + } +} + +void +gdk_window_real_destroy (GdkWindow *window) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + + if (private->extension_events != 0) + gdk_input_window_destroy (window); + + if (private->ref_count == 0) + { + gdk_xid_table_remove (private->xwindow); + g_free (window); + } +} + +GdkWindow* +gdk_window_ref (GdkWindow *window) +{ + GdkWindowPrivate *private = (GdkWindowPrivate *)window; + g_return_if_fail (window != NULL); + + private->ref_count += 1; + return window; +} + +void +gdk_window_unref (GdkWindow *window) +{ + GdkWindowPrivate *private = (GdkWindowPrivate *)window; + g_return_if_fail (window != NULL); + + private->ref_count -= 1; + if (private->ref_count == 0) + gdk_window_real_destroy (window); +} + +void +gdk_window_show (GdkWindow *window) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + if (!private->destroyed) + { + XRaiseWindow (private->xdisplay, private->xwindow); + XMapWindow (private->xdisplay, private->xwindow); + } +} + +void +gdk_window_hide (GdkWindow *window) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + if (!private->destroyed) + XUnmapWindow (private->xdisplay, private->xwindow); +} + +void +gdk_window_move (GdkWindow *window, + gint x, + gint y) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + XMoveWindow (private->xdisplay, private->xwindow, x, y); + + if (private->window_type == GDK_WINDOW_CHILD) + { + private->x = x; + private->y = y; + } +} + +void +gdk_window_resize (GdkWindow *window, + gint width, + gint height) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + if (width < 1) + width = 1; + if (height < 1) + height = 1; + + private = (GdkWindowPrivate*) window; + + if (!private->destroyed && + ((private->resize_count > 0) || + (private->width != (guint16) width) || + (private->height != (guint16) height))) + { + XResizeWindow (private->xdisplay, private->xwindow, width, height); + private->resize_count += 1; + + if (private->window_type == GDK_WINDOW_CHILD) + { + private->width = width; + private->height = height; + } + } +} + +void +gdk_window_move_resize (GdkWindow *window, + gint x, + gint y, + gint width, + gint height) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + if (width < 1) + width = 1; + if (height < 1) + height = 1; + + private = (GdkWindowPrivate*) window; + XMoveResizeWindow (private->xdisplay, private->xwindow, x, y, width, height); + + if (!private->destroyed && + (private->window_type == GDK_WINDOW_CHILD)) + { + private->x = x; + private->y = y; + private->width = width; + private->height = height; + } +} + +void +gdk_window_reparent (GdkWindow *window, + GdkWindow *new_parent, + gint x, + gint y) +{ + GdkWindowPrivate *window_private; + GdkWindowPrivate *parent_private; + + g_return_if_fail (window != NULL); + + if (!new_parent) + new_parent = (GdkWindow*) &gdk_root_parent; + + window_private = (GdkWindowPrivate*) window; + parent_private = (GdkWindowPrivate*) new_parent; + + XReparentWindow (window_private->xdisplay, + window_private->xwindow, + parent_private->xwindow, + x, y); +} + +void +gdk_window_clear (GdkWindow *window) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + + XClearWindow (private->xdisplay, private->xwindow); +} + +void +gdk_window_clear_area (GdkWindow *window, + gint x, + gint y, + gint width, + gint height) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + + if (!private->destroyed) + XClearArea (private->xdisplay, private->xwindow, + x, y, width, height, False); +} + +void +gdk_window_clear_area_e (GdkWindow *window, + gint x, + gint y, + gint width, + gint height) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + + if (!private->destroyed) + XClearArea (private->xdisplay, private->xwindow, + x, y, width, height, True); +} + +void +gdk_window_copy_area (GdkWindow *window, + GdkGC *gc, + gint x, + gint y, + GdkWindow *source_window, + gint source_x, + gint source_y, + gint width, + gint height) +{ + GdkWindowPrivate *src_private; + GdkWindowPrivate *dest_private; + GdkGCPrivate *gc_private; + + g_return_if_fail (window != NULL); + g_return_if_fail (gc != NULL); + + if (source_window == NULL) + source_window = window; + + src_private = (GdkWindowPrivate*) source_window; + dest_private = (GdkWindowPrivate*) window; + gc_private = (GdkGCPrivate*) gc; + + if (!src_private->destroyed && !dest_private->destroyed) + { + XCopyArea (dest_private->xdisplay, src_private->xwindow, dest_private->xwindow, + gc_private->xgc, + source_x, source_y, + width, height, + x, y); + } +} + +void +gdk_window_raise (GdkWindow *window) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + + if (!private->destroyed) + XRaiseWindow (private->xdisplay, private->xwindow); +} + +void +gdk_window_lower (GdkWindow *window) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + + if (!private->destroyed) + XLowerWindow (private->xdisplay, private->xwindow); +} + +void +gdk_window_set_user_data (GdkWindow *window, + gpointer user_data) +{ + g_return_if_fail (window != NULL); + + window->user_data = user_data; +} + +void +gdk_window_set_hints (GdkWindow *window, + gint x, + gint y, + gint min_width, + gint min_height, + gint max_width, + gint max_height, + gint flags) +{ + GdkWindowPrivate *private; + XSizeHints size_hints; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + size_hints.flags = 0; + + if (flags & GDK_HINT_POS) + { + size_hints.flags |= PPosition; + size_hints.x = x; + size_hints.y = y; + } + + if (flags & GDK_HINT_MIN_SIZE) + { + size_hints.flags |= PMinSize; + size_hints.min_width = min_width; + size_hints.min_height = min_height; + } + + if (flags & GDK_HINT_MAX_SIZE) + { + size_hints.flags |= PMaxSize; + size_hints.max_width = max_width; + size_hints.max_height = max_height; + } + + if (flags) + XSetWMNormalHints (private->xdisplay, private->xwindow, &size_hints); +} + +void +gdk_window_set_title (GdkWindow *window, + const gchar *title) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + XStoreName (private->xdisplay, private->xwindow, title); + XSetIconName (private->xdisplay, private->xwindow, title); +} + +void +gdk_window_set_background (GdkWindow *window, + GdkColor *color) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + XSetWindowBackground (private->xdisplay, private->xwindow, color->pixel); +} + +void +gdk_window_set_back_pixmap (GdkWindow *window, + GdkPixmap *pixmap, + gint parent_relative) +{ + GdkWindowPrivate *window_private; + GdkPixmapPrivate *pixmap_private; + Pixmap xpixmap; + + g_return_if_fail (window != NULL); + + window_private = (GdkWindowPrivate*) window; + pixmap_private = (GdkPixmapPrivate*) pixmap; + + if (pixmap) + xpixmap = pixmap_private->xwindow; + else + xpixmap = None; + + if (parent_relative) + xpixmap = ParentRelative; + + XSetWindowBackgroundPixmap (window_private->xdisplay, window_private->xwindow, xpixmap); +} + +void +gdk_window_set_cursor (GdkWindow *window, + GdkCursor *cursor) +{ + GdkWindowPrivate *window_private; + GdkCursorPrivate *cursor_private; + Cursor xcursor; + + g_return_if_fail (window != NULL); + + window_private = (GdkWindowPrivate*) window; + cursor_private = (GdkCursorPrivate*) cursor; + + if (!cursor) + xcursor = None; + else + xcursor = cursor_private->xcursor; + + XDefineCursor (window_private->xdisplay, window_private->xwindow, xcursor); +} + +void +gdk_window_set_colormap (GdkWindow *window, + GdkColormap *colormap) +{ + GdkWindowPrivate *window_private; + GdkColormapPrivate *colormap_private; + + g_return_if_fail (window != NULL); + g_return_if_fail (colormap != NULL); + + window_private = (GdkWindowPrivate*) window; + colormap_private = (GdkColormapPrivate*) colormap; + + XSetWindowColormap (window_private->xdisplay, + window_private->xwindow, + colormap_private->xcolormap); + + if (window_private->window_type != GDK_WINDOW_TOPLEVEL) + gdk_window_add_colormap_windows (window); +} + +void +gdk_window_get_user_data (GdkWindow *window, + gpointer *data) +{ + g_return_if_fail (window != NULL); + + *data = window->user_data; +} + +void +gdk_window_get_geometry (GdkWindow *window, + gint *x, + gint *y, + gint *width, + gint *height, + gint *depth) +{ + GdkWindowPrivate *window_private; + Window root; + gint tx; + gint ty; + guint twidth; + guint theight; + guint tborder_width; + guint tdepth; + + if (!window) + window = (GdkWindow*) &gdk_root_parent; + + window_private = (GdkWindowPrivate*) window; + + XGetGeometry (window_private->xdisplay, window_private->xwindow, + &root, &tx, &ty, &twidth, &theight, &tborder_width, &tdepth); + + if (x) + *x = tx; + if (y) + *y = ty; + if (width) + *width = twidth; + if (height) + *height = theight; + if (depth) + *depth = tdepth; +} + +void +gdk_window_get_position (GdkWindow *window, + gint *x, + gint *y) +{ + GdkWindowPrivate *window_private; + + g_return_if_fail (window != NULL); + + window_private = (GdkWindowPrivate*) window; + + if (x) + *x = window_private->x; + if (y) + *y = window_private->y; +} + +void +gdk_window_get_size (GdkWindow *window, + gint *width, + gint *height) +{ + GdkWindowPrivate *window_private; + + g_return_if_fail (window != NULL); + + window_private = (GdkWindowPrivate*) window; + + if (width) + *width = window_private->width; + if (height) + *height = window_private->height; +} + + +GdkVisual* +gdk_window_get_visual (GdkWindow *window) +{ + GdkWindowPrivate *window_private; + XWindowAttributes window_attributes; + + g_return_val_if_fail (window != NULL, NULL); + + window_private = (GdkWindowPrivate*) window; + while (window_private && (window_private->window_type == GDK_WINDOW_PIXMAP)) + window_private = (GdkWindowPrivate*) window_private->parent; + + if (window_private) + { + XGetWindowAttributes (window_private->xdisplay, + window_private->xwindow, + &window_attributes); + + return gdk_visual_lookup (window_attributes.visual); + } + + return NULL; +} + +GdkColormap* +gdk_window_get_colormap (GdkWindow *window) +{ + GdkWindowPrivate *window_private; + XWindowAttributes window_attributes; + + g_return_val_if_fail (window != NULL, NULL); + + window_private = (GdkWindowPrivate*) window; + + XGetWindowAttributes (window_private->xdisplay, + window_private->xwindow, + &window_attributes); + + return gdk_colormap_lookup (window_attributes.colormap); +} + +GdkWindowType +gdk_window_get_type (GdkWindow *window) +{ + GdkWindowPrivate *window_private; + + g_return_val_if_fail (window != NULL, (GdkWindowType) -1); + + window_private = (GdkWindowPrivate*) window; + return window_private->window_type; +} + +gint +gdk_window_get_origin (GdkWindow *window, + gint *x, + gint *y) +{ + GdkWindowPrivate *private; + gint return_val; + Window child; + gint tx, ty; + + g_return_val_if_fail (window != NULL, 0); + + private = (GdkWindowPrivate*) window; + + return_val = XTranslateCoordinates (private->xdisplay, + private->xwindow, + gdk_root_window, + 0, 0, &tx, &ty, + &child); + + if (x) + *x = tx; + if (y) + *y = ty; + + return return_val; +} + +GdkWindow* +gdk_window_get_pointer (GdkWindow *window, + gint *x, + gint *y, + GdkModifierType *mask) +{ + GdkWindowPrivate *private; + GdkWindow *return_val; + Window root; + Window child; + int rootx, rooty; + int winx, winy; + unsigned int xmask; + + if (!window) + window = (GdkWindow*) &gdk_root_parent; + + private = (GdkWindowPrivate*) window; + + return_val = NULL; + if (XQueryPointer (private->xdisplay, private->xwindow, &root, &child, + &rootx, &rooty, &winx, &winy, &xmask)) + { + if (x) *x = winx; + if (y) *y = winy; + if (mask) *mask = xmask; + + if (child) + return_val = gdk_window_lookup (child); + } + + return return_val; +} + +GdkWindow* +gdk_window_get_parent (GdkWindow *window) +{ + g_return_val_if_fail (window != NULL, NULL); + + return ((GdkWindowPrivate*) window)->parent; +} + +GdkWindow* +gdk_window_get_toplevel (GdkWindow *window) +{ + GdkWindowPrivate *private; + + g_return_val_if_fail (window != NULL, NULL); + + private = (GdkWindowPrivate*) window; + + while (private->window_type == GDK_WINDOW_CHILD) + { + window = ((GdkWindowPrivate*) window)->parent; + private = (GdkWindowPrivate*) window; + } + + return window; +} + +GList* +gdk_window_get_children (GdkWindow *window) +{ + GdkWindowPrivate *private; + GdkWindow *child; + GList *children; + Window root; + Window parent; + Window *xchildren; + unsigned int nchildren; + unsigned int i; + + g_return_val_if_fail (window != NULL, NULL); + + private = (GdkWindowPrivate*) window; + + XQueryTree (private->xdisplay, private->xwindow, + &root, &parent, &xchildren, &nchildren); + + children = NULL; + + if (nchildren > 0) + { + for (i = 0; i < nchildren; i++) + { + child = gdk_window_lookup (xchildren[i]); + if (child) + children = g_list_prepend (children, child); + } + + XFree (xchildren); + } + + return children; +} + +GdkEventMask +gdk_window_get_events (GdkWindow *window) +{ + XWindowAttributes attrs; + GdkEventMask event_mask; + int i; + + XGetWindowAttributes (gdk_display, ((GdkWindowPrivate *)window)->xwindow, + &attrs); + + event_mask = 0; + for (i = 0; i < nevent_masks; i++) + { + if (attrs.your_event_mask & event_mask_table[i]) + event_mask |= 1 << (i + 1); + } + + return event_mask; +} + +void +gdk_window_set_events (GdkWindow *window, + GdkEventMask event_mask) +{ + long xevent_mask; + int i; + + xevent_mask = StructureNotifyMask; + for (i = 0; i < nevent_masks; i++) + { + if (event_mask & (1 << (i + 1))) + xevent_mask |= event_mask_table[i]; + } + + XSelectInput (gdk_display, ((GdkWindowPrivate *)window)->xwindow, + xevent_mask); +} + +void +gdk_window_add_colormap_windows (GdkWindow *window) +{ + GdkWindow *toplevel; + GdkWindowPrivate *toplevel_private; + GdkWindowPrivate *window_private; + Window *old_windows; + Window *new_windows; + int i, count; + + g_return_if_fail (window != NULL); + + toplevel = gdk_window_get_toplevel (window); + toplevel_private = (GdkWindowPrivate*) toplevel; + window_private = (GdkWindowPrivate*) window; + + if (!XGetWMColormapWindows (toplevel_private->xdisplay, + toplevel_private->xwindow, + &old_windows, &count)) + { + old_windows = NULL; + count = 0; + } + + for (i = 0; i < count; i++) + if (old_windows[i] == window_private->xwindow) + return; + + new_windows = g_new (Window, count + 1); + + for (i = 0; i < count; i++) + new_windows[i] = old_windows[i]; + new_windows[count] = window_private->xwindow; + + XSetWMColormapWindows (toplevel_private->xdisplay, + toplevel_private->xwindow, + new_windows, count + 1); + + g_free (new_windows); + if (old_windows) + XFree (old_windows); +} + +/* + * This needs the X11 shape extension. + * If not available, simply remove the call to + * XShapeCombineMask. Shaped windows will look + * ugly, but programs still work. Stefan Wille + */ +void +gdk_window_shape_combine_mask (GdkWindow *window, + GdkBitmap *mask, + gint x, gint y) +{ + GdkWindowPrivate *window_private; + GdkWindowPrivate *pixmap_private; + + g_return_if_fail (window != NULL); + g_return_if_fail (mask != NULL); + + window_private = (GdkWindowPrivate*) window; + pixmap_private = (GdkWindowPrivate*) mask; + + XShapeCombineMask (window_private->xdisplay, + window_private->xwindow, + ShapeBounding, + x, y, /* offset */ + (Pixmap)pixmap_private->xwindow, + ShapeSet); +} + +void +gdk_dnd_drag_addwindow (GdkWindow *window) +{ + GdkWindowPrivate *window_private; + + g_return_if_fail (window != NULL); + + window_private = (GdkWindowPrivate *) window; + + if (window_private->dnd_drag_enabled == 1 && gdk_dnd.drag_really == 0) + { + gdk_dnd.drag_numwindows++; + gdk_dnd.drag_startwindows = g_realloc (gdk_dnd.drag_startwindows, + gdk_dnd.drag_numwindows + * sizeof(GdkWindow *)); + gdk_dnd.drag_startwindows[gdk_dnd.drag_numwindows - 1] = window; + window_private->dnd_drag_accepted = 0; + } + else + g_warning ("dnd_really is 1 or drag is not enabled! can't addwindow\n"); +} + +void +gdk_window_dnd_drag_set (GdkWindow *window, + guint8 drag_enable, + gchar **typelist, + guint numtypes) +{ + GdkWindowPrivate *window_private; + int i, wasset = 0; + + g_return_if_fail (window != NULL); + window_private = (GdkWindowPrivate *) window; + + window_private->dnd_drag_enabled = drag_enable ? 1 : 0; + + if (drag_enable) + { + g_return_if_fail(typelist != NULL); + + if (window_private->dnd_drag_data_numtypesavail > 3) + wasset = 1; + window_private->dnd_drag_data_numtypesavail = numtypes; + + window_private->dnd_drag_data_typesavail = + g_realloc (window_private->dnd_drag_data_typesavail, + (numtypes + 1) * sizeof (GdkAtom)); + + for (i = 0; i < numtypes; i++) + { + /* Allow blanket use of ALL to get anything... */ + if (strcmp (typelist[i], "ALL")) + window_private->dnd_drag_data_typesavail[i] = + gdk_atom_intern (typelist[i], FALSE); + else + window_private->dnd_drag_data_typesavail[i] = None; + } + + /* + * set our extended type list if we need to + */ + if (numtypes > 3) + gdk_property_change(window, gdk_dnd.gdk_XdeTypelist, + XA_PRIMARY, 32, GDK_PROP_MODE_REPLACE, + (guchar *)(window_private->dnd_drag_data_typesavail + + (sizeof(GdkAtom) * 3)), + (numtypes - 3) * sizeof(GdkAtom)); + else if (wasset) + gdk_property_delete (window, gdk_dnd.gdk_XdeTypelist); + } + else + { + free (window_private->dnd_drag_data_typesavail); + window_private->dnd_drag_data_typesavail = NULL; + window_private->dnd_drag_data_numtypesavail = 0; + } +} + +void +gdk_window_dnd_drop_set (GdkWindow *window, + guint8 drop_enable, + gchar **typelist, + guint numtypes, + guint8 destructive_op) +{ + GdkWindowPrivate *window_private; + int i; + + g_return_if_fail (window != NULL); + + window_private = (GdkWindowPrivate *) window; + + window_private->dnd_drop_enabled = drop_enable ? 1 : 0; + if (drop_enable) + { + g_return_if_fail(typelist != NULL); + + window_private->dnd_drop_data_numtypesavail = numtypes; + + window_private->dnd_drop_data_typesavail = + g_realloc (window_private->dnd_drop_data_typesavail, + (numtypes + 1) * sizeof (GdkAtom)); + + for (i = 0; i < numtypes; i++) + window_private->dnd_drop_data_typesavail[i] = + gdk_atom_intern (typelist[i], FALSE); + + window_private->dnd_drop_destructive_op = destructive_op; + } +} + +/* + * This is used to reply to a GDK_DRAG_REQUEST event + * (which may be generated by XdeRequest or a confirmed drop... + */ +void +gdk_window_dnd_data_set (GdkWindow *window, + GdkEvent *event, + gpointer data, + gulong data_numbytes) +{ + GdkWindowPrivate *window_private; + XEvent sev; + GdkEventDropDataAvailable tmp_ev; + gchar *tmp; + + g_return_if_fail (window != NULL); + g_return_if_fail (event != NULL); + g_return_if_fail (data != NULL); + g_return_if_fail (data_numbytes > 0); + g_return_if_fail (event->type == GDK_DRAG_REQUEST); + + g_free (event->dragrequest.data_type); + event->dragrequest.data_type = NULL; + + window_private = (GdkWindowPrivate *) window; + g_return_if_fail (window_private->dnd_drag_accepted != 0); + + /* We set the property on our window... */ + gdk_property_change (window, window_private->dnd_drag_data_type, + XA_PRIMARY, 8, GDK_PROP_MODE_REPLACE, data, + data_numbytes); + tmp = gdk_atom_name(window_private->dnd_drag_data_type); + g_print("DnD type %s on window %ld\n", tmp, window_private->xwindow); + g_free(tmp); + + /* + * Then we send the event to tell the receiving window that the + * drop has happened + */ + tmp_ev.u.allflags = 0; + tmp_ev.u.flags.protocol_version = DND_PROTOCOL_VERSION; + tmp_ev.u.flags.isdrop = event->dragrequest.isdrop; + + sev.xclient.type = ClientMessage; + sev.xclient.format = 32; + sev.xclient.window = event->dragrequest.requestor; + sev.xclient.message_type = gdk_dnd.gdk_XdeDataAvailable; + sev.xclient.data.l[0] = window_private->xwindow; + sev.xclient.data.l[1] = tmp_ev.u.allflags; + sev.xclient.data.l[2] = window_private->dnd_drag_data_type; + + if (event->dragrequest.isdrop) + sev.xclient.data.l[3] = event->dragrequest.drop_coords.x + + (event->dragrequest.drop_coords.y << 16); + else + sev.xclient.data.l[3] = 0; + + sev.xclient.data.l[4] = 0; + + XSendEvent (gdk_display, event->dragrequest.requestor, False, + NoEventMask, &sev); +} diff --git a/gdk/x11/gdkx.h b/gdk/x11/gdkx.h new file mode 100644 index 000000000..cb8e33b44 --- /dev/null +++ b/gdk/x11/gdkx.h @@ -0,0 +1,48 @@ +/* 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 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef __GDK_X_H__ +#define __GDK_X_H__ + +#include <gdk/gdkprivate.h> + + +#define GDK_ROOT_WINDOW() gdk_root_window +#define GDK_ROOT_PARENT() &gdk_root_parent +#define GDK_DISPLAY() gdk_display +#define GDK_WINDOW_XDISPLAY(win) (((GdkWindowPrivate*) win)->xdisplay) +#define GDK_WINDOW_XWINDOW(win) (((GdkWindowPrivate*) win)->xwindow) +#define GDK_IMAGE_XDISPLAY(image) (((GdkImagePrivate*) image)->xdisplay) +#define GDK_IMAGE_XIMAGE(image) (((GdkImagePrivate*) image)->ximage) +#define GDK_GC_XDISPLAY(gc) (((GdkGCPrivate*) gc)->xdisplay) +#define GDK_GC_XGC(gc) (((GdkGCPrivate*) gc)->xgc) +#define GDK_COLORMAP_XDISPLAY(cmap) (((GdkColormapPrivate*) cmap)->xdisplay) +#define GDK_COLORMAP_XCOLORMAP(cmap) (((GdkColormapPrivate*) cmap)->xcolormap) +#define GDK_VISUAL_XVISUAL(vis) (((GdkVisualPrivate*) vis)->xvisual) +#define GDK_FONT_XDISPLAY(font) (((GdkFontPrivate*) font)->xdisplay) +#define GDK_FONT_XFONT(font) (((GdkFontPrivate*) font)->xfont) + + +GdkVisual* gdkx_visual_get (VisualID xvisualid); +GdkColormap* gdkx_colormap_get (Colormap xcolormap); +/* Utility function in gdk.c - not sure where it belongs, but it's + needed in more than one place, so make it public */ +Window gdk_get_client_window (Display *dpy, + Window win); + + +#endif /* __GDK_X_H__ */ diff --git a/gdk/x11/gdkxid.c b/gdk/x11/gdkxid.c new file mode 100644 index 000000000..7ee6075c5 --- /dev/null +++ b/gdk/x11/gdkxid.c @@ -0,0 +1,74 @@ +/* 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 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include "gdkprivate.h" + + +static guint gdk_xid_hash (XID *xid); +static gint gdk_xid_compare (XID *a, + XID *b); + + +GHashTable *xid_ht = NULL; + + +void +gdk_xid_table_insert (XID *xid, + gpointer data) +{ + g_return_if_fail (xid != NULL); + + if (!xid_ht) + xid_ht = g_hash_table_new ((GHashFunc) gdk_xid_hash, + (GCompareFunc) gdk_xid_compare); + + g_hash_table_insert (xid_ht, xid, data); +} + +void +gdk_xid_table_remove (XID xid) +{ + if (!xid_ht) + xid_ht = g_hash_table_new ((GHashFunc) gdk_xid_hash, + (GCompareFunc) gdk_xid_compare); + + g_hash_table_remove (xid_ht, &xid); +} + +gpointer +gdk_xid_table_lookup (XID xid) +{ + gpointer data; + + data = g_hash_table_lookup (xid_ht, &xid); + + return data; +} + + +static guint +gdk_xid_hash (XID *xid) +{ + return *xid; +} + +static gint +gdk_xid_compare (XID *a, + XID *b) +{ + return (*a == *b); +} diff --git a/gdk/x11/gxid.c b/gdk/x11/gxid.c new file mode 100644 index 000000000..219c08bfe --- /dev/null +++ b/gdk/x11/gxid.c @@ -0,0 +1,844 @@ +/* + * gxid version 0.3 + * + * Copyright 1997 Owen Taylor <owt1@cornell.edu> +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <signal.h> +#include <sys/time.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <X11/Xlib.h> +#include <X11/extensions/XInput.h> + +#include "gxid_proto.h" + +/* #define DEBUG_CLIENTS */ +/* #define DEBUG_EVENTS */ + +char *program_name; +Display *dpy; +Window root_window; /* default root window of dpy */ +int port = 0; /* port to listen on */ +int socket_fd = 0; /* file descriptor of socket */ +typedef struct GxidWindow_ GxidWindow; + +typedef struct GxidDevice_ GxidDevice; +struct GxidDevice_ { + XID id; + int exclusive; + int ispointer; + + XDevice *xdevice; + int motionnotify_type; + int changenotify_type; +}; + +struct GxidWindow_ { + Window xwindow; + /* Immediate child of root that is ancestor of window */ + Window root_child; + int num_devices; + GxidDevice **devices; +}; + +GxidDevice **devices = NULL; +int num_devices = 0; +GxidWindow **windows = NULL; +int num_windows = 0; + +void +handler(int signal) +{ + fprintf(stderr,"%s: dying on signal %d\n",program_name,signal); + if (socket_fd) + close(socket_fd); + exit(1); +} + +void +init_socket() +{ + struct sockaddr_in sin; + + socket_fd = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP); + if (socket_fd < 0) + { + fprintf (stderr, "%s: error getting socket\n", + program_name); + exit(1); + } + + sin.sin_family = AF_INET; + sin.sin_port = htons(port); + sin.sin_addr.s_addr = INADDR_ANY; + + if (bind(socket_fd,(struct sockaddr *)(&sin), + sizeof(struct sockaddr_in)) < 0) + { + fprintf (stderr,"%s: cannot bind to port %d\n", + program_name,port); + exit(1); + } + + if (listen(socket_fd,5) < 0) + { + fprintf (stderr,"%s: error listening on socket\n", + program_name); + exit(1); + }; +} + +#define NUM_EVENTC 2 +static void +enable_device(GxidDevice *dev) +{ + XEventClass xevc[NUM_EVENTC]; + int num_eventc = NUM_EVENTC; + int i,j; + + if (!dev->xdevice) + { + if (dev->ispointer) return; + + dev->xdevice = XOpenDevice(dpy, dev->id); + if (!dev->xdevice) return; + + DeviceMotionNotify (dev->xdevice, dev->motionnotify_type, + xevc[0]); + ChangeDeviceNotify (dev->xdevice, dev->changenotify_type, + xevc[1]); + + /* compress out zero event classes */ + for (i=0,j=0;i<NUM_EVENTC;i++) + { + if (xevc[i]) { + xevc[j] = xevc[i]; + j++; + } + } + num_eventc = j; + + XSelectExtensionEvent (dpy, root_window, xevc, num_eventc); + } +} + +/* switch the core pointer from whatever it is now to something else, + return true on success, false otherwise */ +static int +switch_core_pointer() +{ + GxidDevice *old_pointer = 0; + GxidDevice *new_pointer = 0; + int result; + int i; + + for (i=0;i<num_devices;i++) + { + if (devices[i]->ispointer) + old_pointer = devices[i]; + else + if (!new_pointer && !devices[i]->exclusive) + new_pointer = devices[i]; + } + + if (!old_pointer || !new_pointer) + return 0; + +#ifdef DEBUG_EVENTS + fprintf(stderr,"gxid: Switching core from %ld to %ld\n", + old_pointer->id,new_pointer->id); +#endif + result = XChangePointerDevice(dpy,new_pointer->xdevice, 0, 1); + if (result != Success) + { + fprintf(stderr,"gxid: Error %d switching core from %ld to %ld\n", + result, old_pointer->id, new_pointer->id); + } + else + { + new_pointer->ispointer = 1; + old_pointer->ispointer = 0; + if (!old_pointer->xdevice) + enable_device(old_pointer); + } + + return 1; +} + +void +disable_device(GxidDevice *dev) +{ + if (dev->xdevice) + { + if (dev->ispointer) + return; + XCloseDevice(dpy,dev->xdevice); + dev->xdevice = 0; + } +} + +GxidDevice * +init_device(XDeviceInfo *xdevice) +{ + GxidDevice *dev = (GxidDevice *)malloc(sizeof(GxidDevice)); + XAnyClassPtr class; + int num_axes, i; + + dev->id = xdevice->id; + dev->exclusive = 0; + dev->xdevice = NULL; + + dev->ispointer = (xdevice->use == IsXPointer); + + /* step through the classes */ + + num_axes = 0; + class = xdevice->inputclassinfo; + for (i=0;i<xdevice->num_classes;i++) + { + if (class->class == ValuatorClass) + { + XValuatorInfo *xvi = (XValuatorInfo *)class; + num_axes = xvi->num_axes; + } + class = (XAnyClassPtr)(((char *)class) + class->length); + } + + /* return NULL if insufficient axes */ + if (num_axes < 2) + { + free((void *)dev); + return NULL; + } + + if (!dev->ispointer) + enable_device(dev); + return dev; +} + +void +init_xinput() +{ + char **extensions; + XDeviceInfo *xdevices; + int num_xdevices; + int num_extensions; + int i; + + extensions = XListExtensions(dpy, &num_extensions); + for (i = 0; i < num_extensions && + (strcmp(extensions[i], "XInputExtension") != 0); i++); + XFreeExtensionList(extensions); + if (i == num_extensions) /* XInput extension not found */ + { + fprintf(stderr,"XInput extension not found\n"); + exit(1); + } + + xdevices = XListInputDevices(dpy, &num_xdevices); + devices = (GxidDevice **)malloc(num_xdevices * sizeof(GxidDevice *)); + + num_devices = 0; + for(i=0; i<num_xdevices; i++) + { + GxidDevice *dev = init_device(&xdevices[i]); + if (dev) + devices[num_devices++] = dev; + } + XFreeDeviceList(xdevices); +} + +/* If this routine needs fixing, the corresponding routine + in gdkinputgxi.h will need it too. */ + +Window +gxi_find_root_child(Display *dpy, Window w) +{ + Window root,parent; + Window *children; + int nchildren; + + parent = w; + do + { + w = parent; + XQueryTree(dpy,w,&root,&parent,&children,&nchildren); + if (children) XFree(children); + } + while (parent != root); + + return w; +} + +int +handle_claim_device(GxidClaimDevice *msg) +{ + int i,j; + XID devid = ntohl(msg->device); + XID winid = ntohl(msg->window); + int exclusive = ntohl(msg->exclusive); + GxidDevice *device = NULL; + GxidWindow *window = NULL; + +#ifdef DEBUG_CLIENTS + fprintf(stderr,"device %ld claimed (window 0x%lx)\n",devid,winid); +#endif + + for (i=0;i<num_devices;i++) + { + if (devices[i]->id == devid) + { + device = devices[i]; + break; + } + } + if (!device) + { + fprintf(stderr,"%s: Unknown device id %ld\n",program_name,devid); + return GXID_RETURN_ERROR; + } + + if (device->exclusive) + { + /* already in use */ + fprintf(stderr, + "%s: Device %ld already claimed in exclusive mode\n", + program_name,devid); + return GXID_RETURN_ERROR; + } + + if (exclusive) + { + for (i=0;i<num_windows;i++) + { + for (j=0;j<windows[i]->num_devices;j++) + if (windows[i]->devices[j]->id == devid) + { + /* already in use */ + fprintf(stderr, + "%s: Can't establish exclusive use of device %ld\n", + program_name,devid); + return GXID_RETURN_ERROR; + } + } + if (device->ispointer) + if (!switch_core_pointer()) + { + fprintf(stderr, + "%s: Can't free up core pointer %ld\n", + program_name,devid); + return GXID_RETURN_ERROR; + } + + device->exclusive = 1; + disable_device(device); + XSelectInput(dpy,winid,StructureNotifyMask); + } + else /* !exclusive */ + { + /* FIXME: this is a bit improper. We probably should do this only + when a window is first claimed. But we might be fooled if + an old client died without releasing it's windows. So until + we look for client-window closings, do it here + + (We do look for closings now...) + */ + + XSelectInput(dpy,winid,EnterWindowMask|StructureNotifyMask); + } + + for (i=0;i<num_windows;i++) + { + if (windows[i]->xwindow == winid) + { + window = windows[i]; + break; + } + } + + /* Create window structure if no devices have been previously + claimed on it */ + if (!window) + { + num_windows++; + windows = (GxidWindow **)realloc(windows, + sizeof(GxidWindow*)*num_windows); + window = (GxidWindow *)malloc(sizeof(GxidWindow)); + windows[num_windows-1] = window; + + window->xwindow = winid; + window->root_child = gxi_find_root_child(dpy,winid); + window->num_devices = 0; + window->devices = 0; + } + + + for (i=0;i<window->num_devices;i++) + { + if (window->devices[i] == device) + return GXID_RETURN_OK; + } + + window->num_devices++; + window->devices = (GxidDevice **)realloc(window->devices, + sizeof(GxidDevice*)*num_devices); + /* we need add the device to the window */ + window->devices[i] = device; + + return GXID_RETURN_OK; +} + +int +handle_release_device(GxidReleaseDevice *msg) +{ + int i,j; + XID devid = ntohl(msg->device); + XID winid = ntohl(msg->window); + + GxidDevice *device = NULL; + +#ifdef DEBUG_CLIENTS + fprintf(stderr,"device %ld released (window 0x%lx)\n",devid,winid); +#endif + + for (i=0;i<num_devices;i++) + { + if (devices[i]->id == devid) + { + device = devices[i]; + break; + } + } + if (!device) + { + fprintf(stderr,"%s: Unknown device id %ld\n",program_name,devid); + return GXID_RETURN_ERROR; + } + + for (i=0;i<num_windows;i++) + { + GxidWindow *w = windows[i]; + + if (w->xwindow == winid) + for (j=0;j<w->num_devices;j++) + if (w->devices[j]->id == devid) + { + if (j<w->num_devices-1) + w->devices[j] = w->devices[w->num_devices-1]; + w->num_devices--; + + if (w->num_devices == 0) + { + if (i<num_windows-1) + windows[i] = windows[num_windows-1]; + num_windows--; + + free((void *)w); + /* FIXME: should we deselect input? But what + what if window is already destroyed */ + } + + if (device->exclusive) + { + device->exclusive = 0; + enable_device(device); + } + return GXID_RETURN_OK; + } + } + + /* device/window combination not found */ + fprintf(stderr, + "%s: Device %ld not claimed for window 0x%lx\n", + program_name,devid,winid); + return GXID_RETURN_ERROR; +} + +void +handle_connection() +{ + GxidMessage msg; + GxidU32 type; + int length; + GxidI32 retval; + + int conn_fd; + struct sockaddr_in sin; + int sin_length; + int count; + + sin_length = sizeof(struct sockaddr_in); + conn_fd = accept(socket_fd,(struct sockaddr *)&sin,&sin_length); + if (conn_fd < 0) + { + fprintf(stderr,"%s: Error accepting connection\n", + program_name); + exit(1); + } + + /* read type and length of message */ + + count = read(conn_fd,(char *)&msg,2*sizeof(GxidU32)); + if (count != 2*sizeof(GxidU32)) + { + fprintf(stderr,"%s: Error reading message header\n", + program_name); + close(conn_fd); + return; + } + type = ntohl(msg.any.type); + length = ntohl(msg.any.length); + + /* read rest of message */ + + if (length > sizeof(GxidMessage)) + { + fprintf(stderr,"%s: Bad message length\n", + program_name); + close(conn_fd); + return; + } + + count = read(conn_fd,2*sizeof(GxidU32) + (char *)&msg, + length - 2*sizeof(GxidU32)); + if (count != length - 2*sizeof(GxidU32)) + { + fprintf(stderr,"%s: Error reading message body\n", + program_name); + close(conn_fd); + return; + } + + switch (type) + { + case GXID_CLAIM_DEVICE: + retval = handle_claim_device((GxidClaimDevice *)&msg); + break; + case GXID_RELEASE_DEVICE: + retval = handle_release_device((GxidReleaseDevice *)&msg); + break; + default: + fprintf(stderr,"%s: Unknown message type: %ld (ignoring)\n", + program_name,type); + close(conn_fd); + return; + } + + count = write(conn_fd,&retval,sizeof(GxidI32)); + if (count != sizeof(GxidI32)) + { + fprintf(stderr,"%s: Error writing return code\n", + program_name); + } + + close(conn_fd); +} + +void +handle_motion_notify(XDeviceMotionEvent *event) +{ + int i,j; + GxidDevice *old_device = NULL; + GxidDevice *new_device = NULL; + Window w, root, child; + int root_x, root_y, x, y, mask; + + for (j=0;j<num_devices;j++) + { + if (devices[j]->ispointer) + old_device = devices[j]; + if (devices[j]->id == event->deviceid) + new_device = devices[j]; + } + + if (new_device && !new_device->exclusive && !new_device->ispointer) + { + /* make sure we aren't stealing the pointer back from a slow + client */ + child = root_window; + do + { + w = child; + /* FIXME: this fails disasterously if child vanishes between + calls. (Which is prone to happening since we get events + on root just as the client exits) */ + + XQueryPointer(dpy,w,&root,&child,&root_x,&root_y, + &x,&y,&mask); + } + while (child != None); + + for (i=0;i<num_windows;i++) + if (windows[i]->xwindow == w) + for (j=0;j<windows[i]->num_devices;j++) + if (windows[i]->devices[j] == new_device) + return; + + /* FIXME: do something smarter with axes */ + XChangePointerDevice(dpy,new_device->xdevice, 0, 1); + new_device->ispointer = 1; + + old_device->ispointer = 0; + if (!old_device->xdevice) + enable_device(old_device); + } +} + +void +handle_change_notify(XChangeDeviceNotifyEvent *event) +{ + int j; + GxidDevice *old_device = NULL; + GxidDevice *new_device = NULL; + + + for (j=0;j<num_devices;j++) + { + if (devices[j]->ispointer) + old_device = devices[j]; + if (devices[j]->id == event->deviceid) + new_device = devices[j]; + } + +#ifdef DEBUG_EVENTS + fprintf(stderr,"gxid: ChangeNotify event; old = %ld; new = %ld\n", + old_device->id, new_device->id); +#endif + + if (old_device != new_device) + { + new_device->ispointer = 1; + + old_device->ispointer = 0; + if (!old_device->xdevice) + enable_device(old_device); + } +} + +void +handle_enter_notify(XEnterWindowEvent *event, GxidWindow *window) +{ + int i; + GxidDevice *old_pointer = NULL; + for (i=0;i<num_devices;i++) + { + if (devices[i]->ispointer) + { + old_pointer = devices[i]; + break; + } + } + +#ifdef DEBUG_EVENTS + fprintf(stderr,"gxid: Enter event; oldpointer = %ld\n", + old_pointer->id); +#endif + + if (old_pointer) + for (i=0;i<window->num_devices;i++) + { + if (window->devices[i] == old_pointer) + { + switch_core_pointer(); + break; + } + } +} + +void +handle_destroy_notify(XDestroyWindowEvent *event) +{ + int i,j; + + for (i=0;i<num_windows;i++) + if (windows[i]->xwindow == event->window) + { + GxidWindow *w = windows[i]; + + for (j=0;j<w->num_devices;j++) + { +#ifdef DEBUG_CLIENTS + fprintf(stderr,"device %ld released on destruction of window 0x%lx.\n", + w->devices[j]->id,w->xwindow); +#endif + + if (w->devices[j]->exclusive) + { + w->devices[j]->exclusive = 0; + enable_device(devices[j]); + } + } + + if (i<num_windows-1) + windows[i] = windows[num_windows-1]; + num_windows--; + + if (w->devices) + free((void *)w->devices); + free((void *)w); + /* FIXME: should we deselect input? But what + what if window is already destroyed */ + + return; + } +} + +void +handle_xevent() +{ + int i; + XEvent event; + + XNextEvent (dpy, &event); + +#ifdef DEBUG_EVENTS + fprintf(stderr,"Event - type = %d; window = 0x%lx\n", + event.type,event.xany.window); +#endif + + if (event.type == ConfigureNotify) + { +#ifdef DEBUG_EVENTS + XConfigureEvent *xce = (XConfigureEvent *)&event; + fprintf(stderr," configureNotify: window = 0x%lx\n",xce->window); +#endif + } + else if (event.type == EnterNotify) + { + /* pointer entered a claimed window */ + for (i=0;i<num_windows;i++) + { + if (event.xany.window == windows[i]->xwindow) + handle_enter_notify((XEnterWindowEvent *)&event,windows[i]); + } + } + else if (event.type == DestroyNotify) + { + /* A claimed window was destroyed */ + for (i=0;i<num_windows;i++) + { + if (event.xany.window == windows[i]->xwindow) + handle_destroy_notify((XDestroyWindowEvent *)&event); + } + } + else + for (i=0;i<num_devices;i++) + { + if (event.type == devices[i]->motionnotify_type) + { + handle_motion_notify((XDeviceMotionEvent *)&event); + break; + } + else if (event.type == devices[i]->changenotify_type) + { + handle_change_notify((XChangeDeviceNotifyEvent *)&event); + break; + } + } +} + +void +usage() +{ + fprintf(stderr,"Usage: %s [-d display] [-p --gxid-port port]\n", + program_name); + exit(1); +} + +int +main(int argc, char **argv) +{ + int i; + char *display_name = NULL; + fd_set readfds; + + program_name = argv[0]; + + for (i=1;i<argc;i++) + { + if (!strcmp(argv[i],"-d")) + { + if (++i >= argc) usage(); + display_name = argv[i]; + } + else if (!strcmp(argv[i],"--gxid-port") || + !strcmp(argv[i],"-p")) + { + if (++i >= argc) usage(); + port = atoi(argv[i]); + break; + } + else + usage(); + } + + if (!port) + { + char *t = getenv("GXID_PORT"); + if (t) + port = atoi(t); + else + port = 6951; + } + /* set up a signal handler so we can clean up if killed */ + + signal(SIGTERM,handler); + signal(SIGINT,handler); + + /* initialize the X connection */ + + dpy = XOpenDisplay (display_name); + if (!dpy) + { + fprintf (stderr, "%s: unable to open display '%s'\n", + program_name, XDisplayName (display_name)); + exit (1); + } + + root_window = DefaultRootWindow(dpy); + + /* We'll want to do this in the future if we are to support + gxid monitoring visibility information for clients */ +#if 0 + XSelectInput(dpy,root_window,SubstructureNotifyMask); +#endif + init_xinput(); + + /* set up our server connection */ + + init_socket(); + + /* main loop */ + + if (XPending(dpy)) /* this seems necessary to get things + in sync */ + handle_xevent(); + while (1) + { + + FD_ZERO(&readfds); + FD_SET(ConnectionNumber(dpy),&readfds); + FD_SET(socket_fd,&readfds); + + if (select(8*sizeof(readfds),&readfds, + (fd_set *)0,(fd_set *)0, (struct timeval *)0) < 0) + { + fprintf(stderr,"Error in select\n"); + exit(1); + } + + if (FD_ISSET(socket_fd,&readfds)) + handle_connection(socket_fd); + + while (XPending(dpy)) + handle_xevent(); + } + + XCloseDisplay (dpy); + exit (0); +} diff --git a/gdk/x11/gxid_lib.c b/gdk/x11/gxid_lib.c new file mode 100644 index 000000000..357b76451 --- /dev/null +++ b/gdk/x11/gxid_lib.c @@ -0,0 +1,116 @@ +/* + * gxid version 0.3 + * + * Copyright 1997 Owen Taylor <owt1@cornell.edu> +*/ + +#include "../config.h" + +#ifdef XINPUT_GXI + +#include <stdio.h> +#include <unistd.h> +#include <sys/time.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <netdb.h> + +#include "gxid_lib.h" + +/* handles mechanics of communicating with a client */ +static int +gxid_send_message(char *host, int port, GxidMessage *msg) +{ + int socket_fd; + struct sockaddr_in sin; + int count; + GxidI32 retval; + struct hostent *he; + + if (!port) port = 6951; + + if (!host || strcmp(host,"localhost") ) + { + /* looking it up as localhost can be _SLOW_ on ppp systems */ + /* FIXME: Could localhost be anything other than loopback? */ + host = "127.0.0.1"; + } + + he = gethostbyname(host); + if (!he) + { + fprintf(stderr,"gxid_lib: error looking up %s\n",host); + return GXID_RETURN_ERROR; + } + + sin.sin_family = he->h_addrtype; + sin.sin_port = htons(port); + memcpy(&sin.sin_addr,he->h_addr_list[0],he->h_length); + + socket_fd = socket(AF_INET,SOCK_STREAM,0); + if (socket_fd < 0) + { + fprintf(stderr,"gxid_lib: can't get socket"); + return GXID_RETURN_ERROR; + } + + if (connect(socket_fd, (struct sockaddr *)&sin, + sizeof sin) < 0) + { + fprintf(stderr,"gxid_lib: can't connect to %s:%d\n",host,port); + close(socket_fd); + return GXID_RETURN_ERROR; + } + + count = write(socket_fd,(char *)msg,ntohl(msg->any.length)); + if (count != ntohl(msg->any.length)) + { + fprintf(stderr,"gxid_lib: error writing"); + close(socket_fd); + return GXID_RETURN_ERROR; + } + + /* now read the return code */ + count = read(socket_fd,(char *)&retval,sizeof(GxidI32)); + if (count != sizeof(GxidI32)) + { + fprintf(stderr,"gxid_lib: error reading return code"); + close(socket_fd); + return GXID_RETURN_ERROR; + } + + close (socket_fd); + return ntohl(retval); +} + +/* claim a device. If exclusive, device is claimed exclusively */ +int +gxid_claim_device(char *host, int port, GxidU32 device, GxidU32 window, + int exclusive) +{ + GxidClaimDevice msg; + msg.type = htonl(GXID_CLAIM_DEVICE); + msg.length = htonl(sizeof(GxidClaimDevice)); + msg.device = htonl(device); + msg.window = htonl(window); + msg.exclusive = htonl(exclusive); + + return gxid_send_message(host,port,(GxidMessage *)&msg); +} + +/* release a device/window pair */ +int +gxid_release_device(char *host, int port, GxidU32 device, GxidU32 window) +{ + GxidReleaseDevice msg; + msg.type = htonl(GXID_RELEASE_DEVICE); + msg.length = htonl(sizeof(GxidReleaseDevice)); + msg.device = htonl(device); + msg.window = htonl(window); + + return gxid_send_message(host,port,(GxidMessage *)&msg); +} + +#endif /* XINPUT_GXI */ + diff --git a/gdk/x11/gxid_lib.h b/gdk/x11/gxid_lib.h new file mode 100644 index 000000000..6a7103bbe --- /dev/null +++ b/gdk/x11/gxid_lib.h @@ -0,0 +1,6 @@ +#include "gxid_proto.h" + +int gxid_claim_device(char *host, int port, + GxidU32 device, GxidU32 window, int exclusive); +int gxid_release_device(char *host, int port, GxidU32 device, + GxidU32 window); diff --git a/gdk/x11/gxid_proto.h b/gdk/x11/gxid_proto.h new file mode 100644 index 000000000..24959b806 --- /dev/null +++ b/gdk/x11/gxid_proto.h @@ -0,0 +1,39 @@ +#define GXID_CLAIM_DEVICE 1 +#define GXID_RELEASE_DEVICE 2 + +#define GXID_RETURN_OK 0 +#define GXID_RETURN_ERROR -1 + +typedef struct GxidClaimDevice_ GxidClaimDevice; +typedef struct GxidReleaseDevice_ GxidReleaseDevice; +typedef struct GxidMessageAny_ GxidMessageAny; +typedef union GxidMessage_ GxidMessage; + +typedef unsigned long GxidU32; +typedef long GxidI32; + +struct GxidClaimDevice_ { + GxidU32 type; + GxidU32 length; + GxidU32 device; + GxidU32 window; + GxidU32 exclusive; +}; + +struct GxidReleaseDevice_ { + GxidU32 type; + GxidU32 length; + GxidU32 device; + GxidU32 window; +}; + +struct GxidMessageAny_ { + GxidU32 type; + GxidU32 length; +}; + +union GxidMessage_ { + GxidMessageAny any; + GxidClaimDevice claim; + GxidReleaseDevice release; +}; |