forked from AuroraMiddleware/gtk
33447a3856
Mon Dec 7 03:08:39 1998 Tim Janik <timj@gtk.org> * gtk/gtktypeutils.h: * gtk/gtktypeutils.c: reverted marius change to expose the type systems internal type info data to the user. if such functionality is required we should provide wrapped accessors, ala gtk_signal_query(). * gtk/gtksignal.c (gtk_signal_connect_by_type): reverted marius change, since it destroys the possibility to implement automatic marshaller lookups some day, and it also disables third party code's ability to connect to any signal. also the GtkTypeInfo structures are dynamically allocated memory portions, so only the type system is really allowed to access that stuff. Mon Dec 7 01:32:18 1998 Tim Janik <timj@gtk.org> * gtk/gtkfilesel.c (gtk_file_selection_key_press): always intercept the Tab key on the entry. the focus shouldn't get lost even if completion is attempted from an empty entry, since an empty entry string does indeed have a valid completion meaning (complete all). (gtk_file_selection_init): cast the gchar array parameter in calls to gtk_clist_new_with_titles() to quit compiler warnings. (check_dir): the no_stat_dirs struct must not be const, since we do indeed modify its contents. * gtk/testgtk.c (event_watcher): adapted prototype to fit new emission hook semantics. * gtk/gtksignal.h: * gtk/gtksignal.c: changed emission allocation, so we don't use a doubly linked list but link ourselfs (singly linked). changed emission hooks, they get the emision parameters passed as well now and are emitted during the actuall signal emission (after the RUN_FIRST class method, but prior to RUN_FIRST handlers). the existing restrictions do still apply to signal emission hooks, i.e. an emission may not be stopped or restarted from an emission hook. due to possibly huge perfomance impacts, frequent use of emision hooks is also not recommended. (gtk_signal_next_and_invalidate): added an assertments which explicits what the code assumes anyways: a maximum amount of 65535 signals. * gtk/gtkcontainer.h: deprecated gtk_container_foreach_interp(), gtk_container_foreach_full() should be used instead. * gtk/gtkmain.h: deprecated gtk_timeout_add_interp and gtk_idle_add_interp, since we provide _full variants. * gtk/gtksignal.h: deprecated gtk_signal_connect_interp(), we provide gtk_signal_connect_full() for long enough now.
1876 lines
44 KiB
C
1876 lines
44 KiB
C
/* GTK - The GIMP Toolkit
|
|
* 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., 59 Temple Place - Suite 330,
|
|
* Boston, MA 02111-1307, USA.
|
|
*/
|
|
#include <X11/Xlocale.h> /* so we get the right setlocale */
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <gmodule.h>
|
|
#include "gtkbutton.h"
|
|
#include "gtkdnd.h"
|
|
#include "gtkfeatures.h"
|
|
#include "gtkhscrollbar.h"
|
|
#include "gtkhseparator.h"
|
|
#include "gtkmain.h"
|
|
#include "gtkpreview.h"
|
|
#include "gtkrc.h"
|
|
#include "gtkselection.h"
|
|
#include "gtksignal.h"
|
|
#include "gtktable.h"
|
|
#include "gtktext.h"
|
|
#include "gtkvbox.h"
|
|
#include "gtkvscrollbar.h"
|
|
#include "gtkwidget.h"
|
|
#include "gtkwindow.h"
|
|
#include "gtkprivate.h"
|
|
#include "gdk/gdki18n.h"
|
|
#include "config.h"
|
|
#include "gtkdebug.h"
|
|
|
|
|
|
/* Private type definitions
|
|
*/
|
|
typedef struct _GtkInitFunction GtkInitFunction;
|
|
typedef struct _GtkQuitFunction GtkQuitFunction;
|
|
typedef struct _GtkTimeoutFunction GtkTimeoutFunction;
|
|
typedef struct _GtkIdleHook GtkIdleHook;
|
|
typedef struct _GtkInputFunction GtkInputFunction;
|
|
typedef struct _GtkKeySnooperData GtkKeySnooperData;
|
|
|
|
struct _GtkInitFunction
|
|
{
|
|
GtkFunction function;
|
|
gpointer data;
|
|
};
|
|
|
|
struct _GtkQuitFunction
|
|
{
|
|
guint id;
|
|
guint main_level;
|
|
GtkCallbackMarshal marshal;
|
|
GtkFunction function;
|
|
gpointer data;
|
|
GtkDestroyNotify destroy;
|
|
};
|
|
|
|
struct _GtkTimeoutFunction
|
|
{
|
|
guint tag;
|
|
guint32 start;
|
|
guint32 interval;
|
|
guint32 originterval;
|
|
GtkFunction function;
|
|
GtkCallbackMarshal marshal;
|
|
gpointer data;
|
|
GtkDestroyNotify destroy;
|
|
};
|
|
|
|
enum
|
|
{
|
|
GTK_HOOK_MARSHAL = 1 << (G_HOOK_FLAG_USER_SHIFT)
|
|
};
|
|
|
|
struct _GtkIdleHook
|
|
{
|
|
GHook hook;
|
|
gint priority;
|
|
};
|
|
#define GTK_IDLE_HOOK(hook) ((GtkIdleHook*) hook)
|
|
|
|
struct _GtkInputFunction
|
|
{
|
|
GtkCallbackMarshal callback;
|
|
gpointer data;
|
|
GtkDestroyNotify destroy;
|
|
};
|
|
|
|
struct _GtkKeySnooperData
|
|
{
|
|
GtkKeySnoopFunc func;
|
|
gpointer func_data;
|
|
guint id;
|
|
};
|
|
|
|
static void gtk_exit_func (void);
|
|
static void gtk_invoke_hook (GHookList *hook_list,
|
|
GHook *hook);
|
|
static void gtk_handle_idles (void);
|
|
static gboolean gtk_finish_idles (void);
|
|
static gint gtk_quit_invoke_function (GtkQuitFunction *quitf);
|
|
static void gtk_quit_destroy (GtkQuitFunction *quitf);
|
|
static void gtk_timeout_insert (GtkTimeoutFunction *timeoutf);
|
|
static void gtk_handle_current_timeouts (guint32 the_time);
|
|
static gint gtk_invoke_key_snoopers (GtkWidget *grab_widget,
|
|
GdkEvent *event);
|
|
static void gtk_handle_timeouts (void);
|
|
static void gtk_handle_timer (void);
|
|
static void gtk_propagate_event (GtkWidget *widget,
|
|
GdkEvent *event);
|
|
#if 0
|
|
static void gtk_error (gchar *str);
|
|
static void gtk_warning (gchar *str);
|
|
static void gtk_message (gchar *str);
|
|
static void gtk_print (gchar *str);
|
|
#endif
|
|
|
|
static gint gtk_timeout_remove_from_list (GList **list,
|
|
guint tag,
|
|
gint remove_link);
|
|
|
|
static gint gtk_timeout_compare (gconstpointer a,
|
|
gconstpointer b);
|
|
|
|
|
|
const guint gtk_major_version = GTK_MAJOR_VERSION;
|
|
const guint gtk_minor_version = GTK_MINOR_VERSION;
|
|
const guint gtk_micro_version = GTK_MICRO_VERSION;
|
|
const guint gtk_binary_age = GTK_BINARY_AGE;
|
|
const guint gtk_interface_age = GTK_INTERFACE_AGE;
|
|
|
|
static gboolean iteration_done = FALSE;
|
|
static guint gtk_main_loop_level = 0;
|
|
static gint gtk_initialized = FALSE;
|
|
static GdkEvent *next_event = NULL;
|
|
static GList *current_events = NULL;
|
|
|
|
static GSList *grabs = NULL; /* A stack of unique grabs. The grabbing
|
|
* widget is the first one on the list.
|
|
*/
|
|
static GList *init_functions = NULL; /* A list of init functions.
|
|
*/
|
|
static GList *quit_functions = NULL; /* A list of quit functions.
|
|
*/
|
|
|
|
|
|
/* When handling timeouts, the algorithm is to move all of the expired
|
|
* timeouts from timeout_functions to current_timeouts then process
|
|
* them as a batch. If one of the timeouts recursively calls the main
|
|
* loop, then the remainder of the timeouts in current_timeouts will
|
|
* be processed before anything else happens.
|
|
*
|
|
* Each timeout is procesed as follows:
|
|
*
|
|
* - The timeout is removed from current_timeouts
|
|
* - The timeout is pushed on the running_timeouts stack
|
|
* - The timeout is executed
|
|
* - The timeout stack is popped
|
|
* - If the timeout function wasn't removed from the stack while executing,
|
|
* and it returned TRUE, it is added back to timeout_functions, otherwise
|
|
* it is destroyed if necessary.
|
|
*
|
|
* gtk_timeout_remove() works by checking for the timeout in
|
|
* timeout_functions current_timeouts and running_timeouts. If it is
|
|
* found in one of the first two, it is removed and destroyed. If it
|
|
* is found in running_timeouts, it is destroyed and ->data is set to
|
|
* NULL for the stack entry.
|
|
*
|
|
* Idle functions work pretty much identically.
|
|
*/
|
|
|
|
static GList *timeout_functions = NULL; /* A list of timeout functions sorted by
|
|
* when the length of the time interval
|
|
* remaining. Therefore, the first timeout
|
|
* function to expire is at the head of
|
|
* the list and the last to expire is at
|
|
* the tail of the list. */
|
|
/* Prioritized idle callbacks */
|
|
static GHookList idle_hooks = { 0 };
|
|
static GHook *last_idle = NULL;
|
|
|
|
/* The timeouts that are currently being processed
|
|
* by gtk_handle_current_timeouts
|
|
*/
|
|
static GList *current_timeouts = NULL;
|
|
|
|
/* A stack of timeouts that is currently being executed
|
|
*/
|
|
static GList *running_timeouts = NULL;
|
|
|
|
static GMemChunk *timeout_mem_chunk = NULL;
|
|
static GMemChunk *quit_mem_chunk = NULL;
|
|
|
|
static GSList *key_snoopers = NULL;
|
|
|
|
static GdkVisual *gtk_visual; /* The visual to be used in creating new
|
|
* widgets.
|
|
*/
|
|
static GdkColormap *gtk_colormap; /* The colormap to be used in creating new
|
|
* widgets.
|
|
*/
|
|
|
|
guint gtk_debug_flags = 0; /* Global GTK debug flag */
|
|
|
|
#ifdef G_ENABLE_DEBUG
|
|
static const GDebugKey gtk_debug_keys[] = {
|
|
{"objects", GTK_DEBUG_OBJECTS},
|
|
{"misc", GTK_DEBUG_MISC},
|
|
{"signals", GTK_DEBUG_SIGNALS},
|
|
{"dnd", GTK_DEBUG_DND}
|
|
};
|
|
|
|
static const guint gtk_ndebug_keys = sizeof (gtk_debug_keys) / sizeof (GDebugKey);
|
|
|
|
#endif /* G_ENABLE_DEBUG */
|
|
|
|
gchar*
|
|
gtk_check_version (guint required_major,
|
|
guint required_minor,
|
|
guint required_micro)
|
|
{
|
|
if (required_major > GTK_MAJOR_VERSION)
|
|
return "Gtk+ version to old (major mismatch)";
|
|
if (required_major < GTK_MAJOR_VERSION)
|
|
return "Gtk+ version to new (major mismatch)";
|
|
if (required_minor > GTK_MINOR_VERSION)
|
|
return "Gtk+ version to old (minor mismatch)";
|
|
if (required_minor < GTK_MINOR_VERSION)
|
|
return "Gtk+ version to new (minor mismatch)";
|
|
if (required_micro < GTK_MICRO_VERSION - GTK_BINARY_AGE)
|
|
return "Gtk+ version to new (micro mismatch)";
|
|
if (required_micro > GTK_MICRO_VERSION)
|
|
return "Gtk+ version to old (micro mismatch)";
|
|
return NULL;
|
|
}
|
|
|
|
|
|
gint gtk_use_mb = -1;
|
|
|
|
void
|
|
gtk_init (int *argc,
|
|
char ***argv)
|
|
{
|
|
GSList *gtk_modules = NULL;
|
|
GSList *slist;
|
|
gchar *current_locale;
|
|
gchar *env_string = NULL;
|
|
|
|
if (gtk_initialized)
|
|
return;
|
|
|
|
#if 0
|
|
g_set_error_handler (gtk_error);
|
|
g_set_warning_handler (gtk_warning);
|
|
g_set_message_handler (gtk_message);
|
|
g_set_print_handler (gtk_print);
|
|
#endif
|
|
|
|
/* Initialize "gdk". We pass along the 'argc' and 'argv'
|
|
* parameters as they contain information that GDK uses
|
|
*/
|
|
gdk_init (argc, argv);
|
|
|
|
#ifdef G_ENABLE_DEBUG
|
|
env_string = getenv ("GTK_DEBUG");
|
|
if (env_string != NULL)
|
|
{
|
|
gtk_debug_flags = g_parse_debug_string (env_string,
|
|
gtk_debug_keys,
|
|
gtk_ndebug_keys);
|
|
env_string = NULL;
|
|
}
|
|
#endif /* G_ENABLE_DEBUG */
|
|
|
|
env_string = getenv ("GTK_MODULES");
|
|
if (env_string)
|
|
{
|
|
gchar **modules, **as;
|
|
|
|
modules = g_strsplit (env_string, ":", -1);
|
|
for (as = modules; *as; as++)
|
|
{
|
|
if (**as)
|
|
gtk_modules = g_slist_prepend (gtk_modules, *as);
|
|
else
|
|
g_free (*as);
|
|
}
|
|
g_free (modules);
|
|
env_string = NULL;
|
|
}
|
|
|
|
if (argc && argv)
|
|
{
|
|
gint i, j, k;
|
|
|
|
for (i = 1; i < *argc;)
|
|
{
|
|
if (strcmp ("--gtk-module", (*argv)[i]) == 0 ||
|
|
strncmp ("--gtk-module=", (*argv)[i], 13) == 0)
|
|
{
|
|
gchar *module_name = (*argv)[i] + 12;
|
|
|
|
if (*module_name == '=')
|
|
module_name++;
|
|
else
|
|
{
|
|
(*argv)[i] = NULL;
|
|
i += 1;
|
|
module_name = (*argv)[i];
|
|
}
|
|
(*argv)[i] = NULL;
|
|
|
|
gtk_modules = g_slist_prepend (gtk_modules, g_strdup (module_name));
|
|
}
|
|
else if (strcmp ("--g-fatal-warnings", (*argv)[i]) == 0)
|
|
{
|
|
GLogLevelFlags fatal_mask;
|
|
|
|
fatal_mask = g_log_set_always_fatal (G_LOG_FATAL_MASK);
|
|
fatal_mask |= G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL;
|
|
g_log_set_always_fatal (fatal_mask);
|
|
(*argv)[i] = NULL;
|
|
}
|
|
#ifdef G_ENABLE_DEBUG
|
|
else if ((strcmp ("--gtk-debug", (*argv)[i]) == 0) ||
|
|
(strncmp ("--gtk-debug=", (*argv)[i], 12) == 0))
|
|
{
|
|
gchar *equal_pos = strchr ((*argv)[i], '=');
|
|
|
|
if (equal_pos != NULL)
|
|
{
|
|
gtk_debug_flags |= g_parse_debug_string (equal_pos+1,
|
|
gtk_debug_keys,
|
|
gtk_ndebug_keys);
|
|
}
|
|
else if ((i + 1) < *argc && (*argv)[i + 1])
|
|
{
|
|
gtk_debug_flags |= g_parse_debug_string ((*argv)[i+1],
|
|
gtk_debug_keys,
|
|
gtk_ndebug_keys);
|
|
(*argv)[i] = NULL;
|
|
i += 1;
|
|
}
|
|
(*argv)[i] = NULL;
|
|
}
|
|
else if ((strcmp ("--gtk-no-debug", (*argv)[i]) == 0) ||
|
|
(strncmp ("--gtk-no-debug=", (*argv)[i], 15) == 0))
|
|
{
|
|
gchar *equal_pos = strchr ((*argv)[i], '=');
|
|
|
|
if (equal_pos != NULL)
|
|
{
|
|
gtk_debug_flags &= ~g_parse_debug_string (equal_pos+1,
|
|
gtk_debug_keys,
|
|
gtk_ndebug_keys);
|
|
}
|
|
else if ((i + 1) < *argc && (*argv)[i + 1])
|
|
{
|
|
gtk_debug_flags &= ~g_parse_debug_string ((*argv)[i+1],
|
|
gtk_debug_keys,
|
|
gtk_ndebug_keys);
|
|
(*argv)[i] = NULL;
|
|
i += 1;
|
|
}
|
|
(*argv)[i] = NULL;
|
|
}
|
|
#endif /* G_ENABLE_DEBUG */
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Check if there is a good chance the mb functions will handle things
|
|
* correctly - set if either mblen("\xc0", MB_CUR_MAX) == 1 in the
|
|
* C locale, or we're using X's mb functions. (-DX_LOCALE && locale != C)
|
|
*/
|
|
|
|
current_locale = setlocale (LC_CTYPE, NULL);
|
|
|
|
#ifdef X_LOCALE
|
|
if ((strcmp (current_locale, "C")) && (strcmp (current_locale, "POSIX")))
|
|
gtk_use_mb = TRUE;
|
|
else
|
|
#endif /* X_LOCALE */
|
|
{
|
|
/* Detect GNU libc, where mb == UTF8. Not useful unless it's
|
|
* really a UTF8 locale. The below still probably will
|
|
* screw up on Greek, Cyrillic, etc, encoded as UTF8.
|
|
*/
|
|
|
|
wchar_t result;
|
|
gtk_use_mb = TRUE;
|
|
|
|
if ((MB_CUR_MAX == 2) &&
|
|
(mbstowcs (&result, "\xdd\xa5", 1) > 0) &&
|
|
result == 0x765)
|
|
{
|
|
if ((strlen (current_locale) < 4) ||
|
|
g_strcasecmp (current_locale + strlen(current_locale) - 4, "utf8"))
|
|
gtk_use_mb = FALSE;
|
|
}
|
|
}
|
|
|
|
GTK_NOTE (MISC,
|
|
g_message ("%s multi-byte string functions.",
|
|
gtk_use_mb ? "Using" : "Not using"));
|
|
|
|
|
|
/* load gtk modules */
|
|
gtk_modules = g_slist_reverse (gtk_modules);
|
|
for (slist = gtk_modules; slist; slist = slist->next)
|
|
{
|
|
gchar *module_name;
|
|
GModule *module = NULL;
|
|
GtkModuleInitFunc modinit_func = NULL;
|
|
|
|
module_name = slist->data;
|
|
slist->data = NULL;
|
|
if (!(module_name[0] == '/' ||
|
|
(module_name[0] == 'l' &&
|
|
module_name[1] == 'i' &&
|
|
module_name[2] == 'b')))
|
|
{
|
|
gchar *old = module_name;
|
|
|
|
module_name = g_strconcat ("lib", module_name, ".so", NULL);
|
|
g_free (old);
|
|
}
|
|
if (g_module_supported ())
|
|
{
|
|
module = g_module_open (module_name, G_MODULE_BIND_LAZY);
|
|
if (module &&
|
|
g_module_symbol (module, "gtk_module_init", (gpointer*) &modinit_func) &&
|
|
modinit_func)
|
|
{
|
|
if (!g_slist_find (gtk_modules, modinit_func))
|
|
{
|
|
g_module_make_resident (module);
|
|
slist->data = modinit_func;
|
|
}
|
|
else
|
|
{
|
|
g_module_close (module);
|
|
module = NULL;
|
|
}
|
|
}
|
|
}
|
|
if (!modinit_func)
|
|
{
|
|
g_warning ("Failed to load module \"%s\": %s",
|
|
module ? g_module_name (module) : module_name,
|
|
g_module_error ());
|
|
if (module)
|
|
g_module_close (module);
|
|
}
|
|
g_free (module_name);
|
|
}
|
|
|
|
/* Initialize the default visual and colormap to be
|
|
* used in creating widgets. (We want to use the system
|
|
* defaults so as to be nice to the colormap).
|
|
*/
|
|
gtk_visual = gdk_visual_get_system ();
|
|
gtk_colormap = gdk_colormap_get_system ();
|
|
|
|
gtk_type_init ();
|
|
gtk_signal_init ();
|
|
gtk_rc_init ();
|
|
|
|
|
|
/* Register an exit function to make sure we are able to cleanup.
|
|
*/
|
|
g_atexit (gtk_exit_func);
|
|
|
|
/* Set the 'initialized' flag.
|
|
*/
|
|
gtk_initialized = TRUE;
|
|
|
|
/* initialize gtk modules
|
|
*/
|
|
for (slist = gtk_modules; slist; slist = slist->next)
|
|
{
|
|
if (slist->data)
|
|
{
|
|
GtkModuleInitFunc modinit;
|
|
|
|
modinit = slist->data;
|
|
modinit (argc, argv);
|
|
}
|
|
}
|
|
g_slist_free (gtk_modules);
|
|
}
|
|
|
|
void
|
|
gtk_exit (int errorcode)
|
|
{
|
|
/* Only if "gtk" has been initialized should we de-initialize.
|
|
*/
|
|
/* de-initialisation is done by the gtk_exit_funct(),
|
|
* no need to do this here (Alex J.)
|
|
*/
|
|
gdk_exit(errorcode);
|
|
}
|
|
|
|
gchar*
|
|
gtk_set_locale (void)
|
|
{
|
|
return gdk_set_locale ();
|
|
}
|
|
|
|
void
|
|
gtk_main (void)
|
|
{
|
|
GList *tmp_list;
|
|
GList *functions;
|
|
GtkInitFunction *init;
|
|
int old_done;
|
|
|
|
gtk_main_loop_level++;
|
|
|
|
tmp_list = functions = init_functions;
|
|
init_functions = NULL;
|
|
|
|
while (tmp_list)
|
|
{
|
|
init = tmp_list->data;
|
|
tmp_list = tmp_list->next;
|
|
|
|
(* init->function) (init->data);
|
|
g_free (init);
|
|
}
|
|
g_list_free (functions);
|
|
|
|
old_done = iteration_done;
|
|
while (!gtk_main_iteration ())
|
|
;
|
|
iteration_done = old_done;
|
|
|
|
if (quit_functions)
|
|
{
|
|
GList *reinvoke_list = NULL;
|
|
GtkQuitFunction *quitf;
|
|
|
|
while (quit_functions)
|
|
{
|
|
quitf = quit_functions->data;
|
|
|
|
quit_functions = g_list_remove_link (quit_functions, quit_functions);
|
|
|
|
if ((quitf->main_level && quitf->main_level != gtk_main_loop_level) ||
|
|
gtk_quit_invoke_function (quitf))
|
|
{
|
|
reinvoke_list = g_list_prepend (reinvoke_list, quitf);
|
|
}
|
|
else
|
|
{
|
|
g_list_free (tmp_list);
|
|
gtk_quit_destroy (quitf);
|
|
}
|
|
}
|
|
if (reinvoke_list)
|
|
{
|
|
GList *work;
|
|
|
|
work = g_list_last (reinvoke_list);
|
|
if (quit_functions)
|
|
quit_functions->prev = work;
|
|
work->next = quit_functions;
|
|
quit_functions = work;
|
|
}
|
|
}
|
|
|
|
gtk_main_loop_level--;
|
|
}
|
|
|
|
guint
|
|
gtk_main_level (void)
|
|
{
|
|
return gtk_main_loop_level;
|
|
}
|
|
|
|
void
|
|
gtk_main_quit (void)
|
|
{
|
|
iteration_done = TRUE;
|
|
}
|
|
|
|
gint
|
|
gtk_events_pending (void)
|
|
{
|
|
gint result = 0;
|
|
|
|
/* if this function is called from a timeout which will only return
|
|
* if gtk needs processor time, we need to take iteration_done==TRUE
|
|
* into account as well.
|
|
*/
|
|
result = iteration_done;
|
|
result += next_event != NULL;
|
|
result += gdk_events_pending();
|
|
|
|
result += last_idle != NULL;
|
|
result += current_timeouts != NULL;
|
|
|
|
if (!result)
|
|
{
|
|
GHook *hook;
|
|
|
|
hook = g_hook_first_valid (&idle_hooks, FALSE);
|
|
|
|
result += hook && GTK_IDLE_HOOK (hook)->priority <= GTK_PRIORITY_INTERNAL;
|
|
}
|
|
|
|
if (!result && timeout_functions)
|
|
{
|
|
guint32 the_time;
|
|
GtkTimeoutFunction *timeoutf;
|
|
|
|
the_time = gdk_time_get ();
|
|
|
|
timeoutf = timeout_functions->data;
|
|
|
|
result += timeoutf->interval <= (the_time - timeoutf->start);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
gint
|
|
gtk_main_iteration (void)
|
|
{
|
|
return gtk_main_iteration_do (TRUE);
|
|
}
|
|
|
|
gint
|
|
gtk_main_iteration_do (gboolean blocking)
|
|
{
|
|
GtkWidget *event_widget;
|
|
GtkWidget *grab_widget;
|
|
GdkEvent *event = NULL;
|
|
GList *tmp_list;
|
|
|
|
iteration_done = FALSE;
|
|
|
|
/* If this is a recursive call, and there are pending timeouts or
|
|
* idles, finish them, then return immediately to avoid blocking
|
|
* in gdk_event_get()
|
|
*/
|
|
if (current_timeouts)
|
|
{
|
|
gtk_handle_current_timeouts( gdk_time_get());
|
|
|
|
if (iteration_done)
|
|
gdk_flush ();
|
|
|
|
return iteration_done;
|
|
}
|
|
if (last_idle && gtk_finish_idles ())
|
|
{
|
|
if (iteration_done)
|
|
gdk_flush ();
|
|
|
|
return iteration_done;
|
|
}
|
|
|
|
/* If there is a valid event in 'next_event' then move it to 'event'
|
|
*/
|
|
if (next_event)
|
|
{
|
|
event = next_event;
|
|
next_event = NULL;
|
|
}
|
|
|
|
/* If we don't have an event then get one.
|
|
*/
|
|
if (!event)
|
|
{
|
|
/* Handle setting of the "gdk" timer. If there are no
|
|
* timeout functions, then the timer is turned off.
|
|
* If there are timeout functions, then the timer is
|
|
* set to the shortest timeout interval (which is
|
|
* the first timeout function).
|
|
*/
|
|
gtk_handle_timer ();
|
|
|
|
if (blocking)
|
|
event = gdk_event_get ();
|
|
}
|
|
|
|
/* "gdk_event_get" can return FALSE if the timer goes off
|
|
* and no events are pending. Therefore, we should make
|
|
* sure that we got an event before continuing.
|
|
*/
|
|
if (event)
|
|
{
|
|
/* If there are any events pending then get the next one.
|
|
*/
|
|
if (gdk_events_pending () > 0)
|
|
next_event = gdk_event_get ();
|
|
|
|
/* Try to compress enter/leave notify events. These event
|
|
* pairs occur when the mouse is dragged quickly across
|
|
* a window with many buttons (or through a menu). Instead
|
|
* of highlighting and de-highlighting each widget that
|
|
* is crossed it is better to simply de-highlight the widget
|
|
* which contained the mouse initially and highlight the
|
|
* widget which ends up containing the mouse.
|
|
*/
|
|
if (next_event)
|
|
if (((event->type == GDK_ENTER_NOTIFY) ||
|
|
(event->type == GDK_LEAVE_NOTIFY)) &&
|
|
((next_event->type == GDK_ENTER_NOTIFY) ||
|
|
(next_event->type == GDK_LEAVE_NOTIFY)) &&
|
|
(next_event->type != event->type) &&
|
|
(next_event->any.window == event->any.window))
|
|
{
|
|
gdk_event_free (event);
|
|
gdk_event_free (next_event);
|
|
next_event = NULL;
|
|
|
|
goto event_handling_done;
|
|
}
|
|
|
|
/* Find the widget which got the event. We store the widget
|
|
* in the user_data field of GdkWindow's.
|
|
* Ignore the event if we don't have a widget for it, except
|
|
* for GDK_PROPERTY_NOTIFY events which are handled specialy.
|
|
* Though this happens rarely, bogus events can occour
|
|
* for e.g. destroyed GdkWindows.
|
|
*/
|
|
event_widget = gtk_get_event_widget (event);
|
|
if (!event_widget)
|
|
{
|
|
/* To handle selection INCR transactions, we select
|
|
* PropertyNotify events on the requestor window and create
|
|
* a corresponding (fake) GdkWindow so that events get
|
|
* here. There won't be a widget though, so we have to handle
|
|
* them specially
|
|
*/
|
|
if (event->type == GDK_PROPERTY_NOTIFY)
|
|
gtk_selection_incr_event (event->any.window,
|
|
&event->property);
|
|
|
|
gdk_event_free (event);
|
|
|
|
goto event_handling_done;
|
|
}
|
|
|
|
/* Push the event onto a stack of current events for
|
|
* gtk_current_event_get().
|
|
*/
|
|
current_events = g_list_prepend (current_events, event);
|
|
|
|
/* If there is a grab in effect...
|
|
*/
|
|
if (grabs)
|
|
{
|
|
grab_widget = grabs->data;
|
|
|
|
/* If the grab widget is an ancestor of the event widget
|
|
* then we send the event to the original event widget.
|
|
* This is the key to implementing modality.
|
|
*/
|
|
if (GTK_WIDGET_IS_SENSITIVE (event_widget) &&
|
|
gtk_widget_is_ancestor (event_widget, grab_widget))
|
|
grab_widget = event_widget;
|
|
}
|
|
else
|
|
{
|
|
grab_widget = event_widget;
|
|
}
|
|
|
|
/* Not all events get sent to the grabbing widget.
|
|
* The delete, destroy, expose, focus change and resize
|
|
* events still get sent to the event widget because
|
|
* 1) these events have no meaning for the grabbing widget
|
|
* and 2) redirecting these events to the grabbing widget
|
|
* could cause the display to be messed up.
|
|
*
|
|
* Drag events are also not redirected, since it isn't
|
|
* clear what the semantics of that would be.
|
|
*/
|
|
switch (event->type)
|
|
{
|
|
case GDK_NOTHING:
|
|
break;
|
|
|
|
case GDK_DELETE:
|
|
gtk_widget_ref (event_widget);
|
|
if (!gtk_widget_event (event_widget, event) &&
|
|
!GTK_OBJECT_DESTROYED (event_widget))
|
|
gtk_widget_destroy (event_widget);
|
|
gtk_widget_unref (event_widget);
|
|
break;
|
|
|
|
case GDK_DESTROY:
|
|
gtk_widget_ref (event_widget);
|
|
gtk_widget_event (event_widget, event);
|
|
if (!GTK_OBJECT_DESTROYED (event_widget))
|
|
gtk_widget_destroy (event_widget);
|
|
gtk_widget_unref (event_widget);
|
|
break;
|
|
|
|
case GDK_PROPERTY_NOTIFY:
|
|
case GDK_EXPOSE:
|
|
case GDK_NO_EXPOSE:
|
|
case GDK_FOCUS_CHANGE:
|
|
case GDK_CONFIGURE:
|
|
case GDK_MAP:
|
|
case GDK_UNMAP:
|
|
case GDK_SELECTION_CLEAR:
|
|
case GDK_SELECTION_REQUEST:
|
|
case GDK_SELECTION_NOTIFY:
|
|
case GDK_CLIENT_EVENT:
|
|
case GDK_VISIBILITY_NOTIFY:
|
|
gtk_widget_event (event_widget, event);
|
|
break;
|
|
|
|
case GDK_KEY_PRESS:
|
|
case GDK_KEY_RELEASE:
|
|
if (key_snoopers)
|
|
{
|
|
if (gtk_invoke_key_snoopers (grab_widget, event))
|
|
break;
|
|
}
|
|
/* else fall through */
|
|
case GDK_MOTION_NOTIFY:
|
|
case GDK_BUTTON_PRESS:
|
|
case GDK_2BUTTON_PRESS:
|
|
case GDK_3BUTTON_PRESS:
|
|
case GDK_BUTTON_RELEASE:
|
|
case GDK_PROXIMITY_IN:
|
|
case GDK_PROXIMITY_OUT:
|
|
gtk_propagate_event (grab_widget, event);
|
|
break;
|
|
|
|
case GDK_ENTER_NOTIFY:
|
|
if (GTK_WIDGET_IS_SENSITIVE (grab_widget))
|
|
{
|
|
gtk_widget_event (grab_widget, event);
|
|
if (event_widget == grab_widget)
|
|
GTK_PRIVATE_SET_FLAG (event_widget, GTK_LEAVE_PENDING);
|
|
}
|
|
break;
|
|
|
|
case GDK_LEAVE_NOTIFY:
|
|
if (GTK_WIDGET_LEAVE_PENDING (event_widget))
|
|
{
|
|
GTK_PRIVATE_UNSET_FLAG (event_widget, GTK_LEAVE_PENDING);
|
|
gtk_widget_event (event_widget, event);
|
|
}
|
|
else if (GTK_WIDGET_IS_SENSITIVE (grab_widget))
|
|
gtk_widget_event (grab_widget, event);
|
|
break;
|
|
|
|
case GDK_DRAG_STATUS:
|
|
case GDK_DROP_FINISHED:
|
|
gtk_drag_source_handle_event (event_widget, event);
|
|
break;
|
|
case GDK_DRAG_ENTER:
|
|
case GDK_DRAG_LEAVE:
|
|
case GDK_DRAG_MOTION:
|
|
case GDK_DROP_START:
|
|
gtk_drag_dest_handle_event (event_widget, event);
|
|
break;
|
|
}
|
|
|
|
tmp_list = current_events;
|
|
current_events = g_list_remove_link (current_events, tmp_list);
|
|
g_list_free_1 (tmp_list);
|
|
|
|
gdk_event_free (event);
|
|
}
|
|
else
|
|
{
|
|
if (gdk_events_pending() == 0)
|
|
gtk_handle_idles ();
|
|
}
|
|
|
|
event_handling_done:
|
|
|
|
/* Handle timeout functions that may have expired.
|
|
*/
|
|
gtk_handle_timeouts ();
|
|
|
|
if (iteration_done)
|
|
gdk_flush ();
|
|
|
|
return iteration_done;
|
|
}
|
|
|
|
gint
|
|
gtk_true (void)
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
gint
|
|
gtk_false (void)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
void
|
|
gtk_grab_add (GtkWidget *widget)
|
|
{
|
|
g_return_if_fail (widget != NULL);
|
|
|
|
if (!GTK_WIDGET_HAS_GRAB (widget))
|
|
{
|
|
GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_GRAB);
|
|
|
|
grabs = g_slist_prepend (grabs, widget);
|
|
gtk_widget_ref (widget);
|
|
}
|
|
}
|
|
|
|
GtkWidget*
|
|
gtk_grab_get_current (void)
|
|
{
|
|
if (grabs)
|
|
return GTK_WIDGET (grabs->data);
|
|
return NULL;
|
|
}
|
|
|
|
void
|
|
gtk_grab_remove (GtkWidget *widget)
|
|
{
|
|
g_return_if_fail (widget != NULL);
|
|
|
|
if (GTK_WIDGET_HAS_GRAB (widget))
|
|
{
|
|
GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_GRAB);
|
|
|
|
grabs = g_slist_remove (grabs, widget);
|
|
gtk_widget_unref (widget);
|
|
}
|
|
}
|
|
|
|
void
|
|
gtk_init_add (GtkFunction function,
|
|
gpointer data)
|
|
{
|
|
GtkInitFunction *init;
|
|
|
|
init = g_new (GtkInitFunction, 1);
|
|
init->function = function;
|
|
init->data = data;
|
|
|
|
init_functions = g_list_prepend (init_functions, init);
|
|
}
|
|
|
|
guint
|
|
gtk_key_snooper_install (GtkKeySnoopFunc snooper,
|
|
gpointer func_data)
|
|
{
|
|
GtkKeySnooperData *data;
|
|
static guint snooper_id = 1;
|
|
|
|
g_return_val_if_fail (snooper != NULL, 0);
|
|
|
|
data = g_new (GtkKeySnooperData, 1);
|
|
data->func = snooper;
|
|
data->func_data = func_data;
|
|
data->id = snooper_id++;
|
|
key_snoopers = g_slist_prepend (key_snoopers, data);
|
|
|
|
return data->id;
|
|
}
|
|
|
|
void
|
|
gtk_key_snooper_remove (guint snooper_id)
|
|
{
|
|
GtkKeySnooperData *data = NULL;
|
|
GSList *slist;
|
|
|
|
slist = key_snoopers;
|
|
while (slist)
|
|
{
|
|
data = slist->data;
|
|
if (data->id == snooper_id)
|
|
break;
|
|
|
|
slist = slist->next;
|
|
data = NULL;
|
|
}
|
|
if (data)
|
|
key_snoopers = g_slist_remove (key_snoopers, data);
|
|
}
|
|
|
|
static gint
|
|
gtk_invoke_key_snoopers (GtkWidget *grab_widget,
|
|
GdkEvent *event)
|
|
{
|
|
GSList *slist;
|
|
gint return_val = FALSE;
|
|
|
|
slist = key_snoopers;
|
|
while (slist && !return_val)
|
|
{
|
|
GtkKeySnooperData *data;
|
|
|
|
data = slist->data;
|
|
slist = slist->next;
|
|
return_val = (*data->func) (grab_widget, (GdkEventKey*) event, data->func_data);
|
|
}
|
|
|
|
return return_val;
|
|
}
|
|
|
|
guint
|
|
gtk_timeout_add_full (guint32 interval,
|
|
GtkFunction function,
|
|
GtkCallbackMarshal marshal,
|
|
gpointer data,
|
|
GtkDestroyNotify destroy)
|
|
{
|
|
static guint timeout_tag = 1;
|
|
GtkTimeoutFunction *timeoutf;
|
|
|
|
g_return_val_if_fail ((function != NULL) || (marshal != NULL), 0);
|
|
|
|
/* Create a new timeout function structure.
|
|
* The start time is the current time.
|
|
*/
|
|
if (!timeout_mem_chunk)
|
|
timeout_mem_chunk = g_mem_chunk_new ("timeout mem chunk", sizeof (GtkTimeoutFunction),
|
|
1024, G_ALLOC_AND_FREE);
|
|
|
|
timeoutf = g_chunk_new (GtkTimeoutFunction, timeout_mem_chunk);
|
|
|
|
timeoutf->tag = timeout_tag++;
|
|
timeoutf->start = gdk_time_get ();
|
|
timeoutf->interval = interval;
|
|
timeoutf->originterval = interval;
|
|
timeoutf->function = function;
|
|
timeoutf->marshal = marshal;
|
|
timeoutf->data = data;
|
|
timeoutf->destroy = destroy;
|
|
|
|
gtk_timeout_insert (timeoutf);
|
|
|
|
return timeoutf->tag;
|
|
}
|
|
|
|
static void
|
|
gtk_timeout_destroy (GtkTimeoutFunction *timeoutf)
|
|
{
|
|
if (timeoutf->destroy)
|
|
(timeoutf->destroy) (timeoutf->data);
|
|
g_mem_chunk_free (timeout_mem_chunk, timeoutf);
|
|
}
|
|
|
|
guint
|
|
gtk_timeout_add (guint32 interval,
|
|
GtkFunction function,
|
|
gpointer data)
|
|
{
|
|
return gtk_timeout_add_full (interval, function, FALSE, data, NULL);
|
|
}
|
|
|
|
guint
|
|
gtk_timeout_add_interp (guint32 interval,
|
|
GtkCallbackMarshal function,
|
|
gpointer data,
|
|
GtkDestroyNotify destroy)
|
|
{
|
|
g_message ("gtk_timeout_add_interp() is deprecated");
|
|
return gtk_timeout_add_full (interval, NULL, function, data, destroy);
|
|
}
|
|
|
|
/* Search for the specified tag in a list of timeouts. If it
|
|
* is found, destroy the timeout, and either remove the link
|
|
* or set link->data to NULL depending on remove_link
|
|
*/
|
|
static gint
|
|
gtk_timeout_remove_from_list (GList **list, guint tag, gint remove_link)
|
|
{
|
|
GList *tmp_list;
|
|
GtkTimeoutFunction *timeoutf;
|
|
|
|
tmp_list = *list;
|
|
while (tmp_list)
|
|
{
|
|
timeoutf = tmp_list->data;
|
|
|
|
if (timeoutf->tag == tag)
|
|
{
|
|
if (remove_link)
|
|
{
|
|
*list = g_list_remove_link (*list, tmp_list);
|
|
g_list_free (tmp_list);
|
|
}
|
|
else
|
|
tmp_list->data = NULL;
|
|
|
|
gtk_timeout_destroy (timeoutf);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
tmp_list = tmp_list->next;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
void
|
|
gtk_timeout_remove (guint tag)
|
|
{
|
|
|
|
/* Remove a timeout function.
|
|
* (Which, basically, involves searching the
|
|
* list for the tag).
|
|
*/
|
|
|
|
if (gtk_timeout_remove_from_list (&timeout_functions, tag, TRUE))
|
|
return;
|
|
if (gtk_timeout_remove_from_list (¤t_timeouts, tag, TRUE))
|
|
return;
|
|
if (gtk_timeout_remove_from_list (&running_timeouts, tag, FALSE))
|
|
return;
|
|
}
|
|
|
|
guint
|
|
gtk_quit_add_full (guint main_level,
|
|
GtkFunction function,
|
|
GtkCallbackMarshal marshal,
|
|
gpointer data,
|
|
GtkDestroyNotify destroy)
|
|
{
|
|
static guint quit_id = 1;
|
|
GtkQuitFunction *quitf;
|
|
|
|
g_return_val_if_fail ((function != NULL) || (marshal != NULL), 0);
|
|
|
|
if (!quit_mem_chunk)
|
|
quit_mem_chunk = g_mem_chunk_new ("quit mem chunk", sizeof (GtkQuitFunction),
|
|
512, G_ALLOC_AND_FREE);
|
|
|
|
quitf = g_chunk_new (GtkQuitFunction, quit_mem_chunk);
|
|
|
|
quitf->id = quit_id++;
|
|
quitf->main_level = main_level;
|
|
quitf->function = function;
|
|
quitf->marshal = marshal;
|
|
quitf->data = data;
|
|
quitf->destroy = destroy;
|
|
|
|
quit_functions = g_list_prepend (quit_functions, quitf);
|
|
|
|
return quitf->id;
|
|
}
|
|
|
|
gint
|
|
gtk_idle_compare (GHook *new_g_hook,
|
|
GHook *g_sibling)
|
|
{
|
|
GtkIdleHook *new_hook = GTK_IDLE_HOOK (new_g_hook);
|
|
GtkIdleHook *sibling = GTK_IDLE_HOOK (g_sibling);
|
|
|
|
/* We add an extra +1 to the comparision result to make sure
|
|
* that we get inserted at the end of the list of hooks with
|
|
* the same priority.
|
|
*/
|
|
return new_hook->priority - sibling->priority + 1;
|
|
}
|
|
|
|
guint
|
|
gtk_idle_add_full (gint priority,
|
|
GtkFunction function,
|
|
GtkCallbackMarshal marshal,
|
|
gpointer data,
|
|
GtkDestroyNotify destroy)
|
|
{
|
|
GHook *hook;
|
|
GtkIdleHook *ihook;
|
|
|
|
if (function)
|
|
g_return_val_if_fail (marshal == NULL, 0);
|
|
else
|
|
g_return_val_if_fail (marshal != NULL, 0);
|
|
|
|
if (!idle_hooks.seq_id)
|
|
g_hook_list_init (&idle_hooks, sizeof (GtkIdleHook));
|
|
|
|
hook = g_hook_alloc (&idle_hooks);
|
|
ihook = GTK_IDLE_HOOK (hook);
|
|
hook->data = data;
|
|
if (marshal)
|
|
{
|
|
hook->flags |= GTK_HOOK_MARSHAL;
|
|
hook->func = marshal;
|
|
}
|
|
else
|
|
hook->func = function;
|
|
hook->destroy = destroy;
|
|
ihook->priority = priority;
|
|
|
|
/* If we are adding the first idle function, possibly wake up
|
|
* the main thread out of its select().
|
|
*/
|
|
if (!g_hook_first_valid (&idle_hooks, TRUE))
|
|
gdk_threads_wake ();
|
|
|
|
g_hook_insert_sorted (&idle_hooks, hook, gtk_idle_compare);
|
|
|
|
return hook->hook_id;
|
|
}
|
|
|
|
guint
|
|
gtk_idle_add (GtkFunction function,
|
|
gpointer data)
|
|
{
|
|
return gtk_idle_add_full (GTK_PRIORITY_DEFAULT, function, NULL, data, NULL);
|
|
}
|
|
|
|
guint
|
|
gtk_idle_add_priority (gint priority,
|
|
GtkFunction function,
|
|
gpointer data)
|
|
{
|
|
return gtk_idle_add_full (priority, function, NULL, data, NULL);
|
|
}
|
|
|
|
guint
|
|
gtk_idle_add_interp (GtkCallbackMarshal marshal,
|
|
gpointer data,
|
|
GtkDestroyNotify destroy)
|
|
{
|
|
g_message ("gtk_idle_add_interp() is deprecated");
|
|
return gtk_idle_add_full (GTK_PRIORITY_DEFAULT, NULL, marshal, data, destroy);
|
|
}
|
|
|
|
void
|
|
gtk_idle_remove (guint tag)
|
|
{
|
|
g_return_if_fail (tag > 0);
|
|
|
|
if (!g_hook_destroy (&idle_hooks, tag))
|
|
g_warning ("gtk_idle_remove(%d): no such idle function", tag);
|
|
}
|
|
|
|
void
|
|
gtk_idle_remove_by_data (gpointer data)
|
|
{
|
|
GHook *hook;
|
|
|
|
hook = g_hook_find_data (&idle_hooks, TRUE, data);
|
|
if (hook)
|
|
g_hook_destroy_link (&idle_hooks, hook);
|
|
else
|
|
g_warning ("gtk_idle_remove_by_data(%p): no such idle function", data);
|
|
}
|
|
|
|
static gboolean
|
|
gtk_finish_idles (void)
|
|
{
|
|
gboolean idles_called;
|
|
|
|
idles_called = FALSE;
|
|
while (last_idle)
|
|
{
|
|
GHook *hook;
|
|
|
|
hook = g_hook_next_valid (last_idle, FALSE);
|
|
|
|
if (!hook || GTK_IDLE_HOOK (hook)->priority != GTK_IDLE_HOOK (last_idle)->priority)
|
|
{
|
|
g_hook_unref (&idle_hooks, last_idle);
|
|
last_idle = NULL;
|
|
}
|
|
else
|
|
{
|
|
g_hook_unref (&idle_hooks, last_idle);
|
|
last_idle = hook;
|
|
g_hook_ref (&idle_hooks, last_idle);
|
|
|
|
idles_called = TRUE;
|
|
gtk_invoke_hook (&idle_hooks, last_idle);
|
|
}
|
|
}
|
|
|
|
return idles_called;
|
|
}
|
|
|
|
static void
|
|
gtk_handle_idles (void)
|
|
{
|
|
GHook *hook;
|
|
|
|
/* Caller must already have called gtk_finish_idles() if necessary
|
|
*/
|
|
g_assert (last_idle == NULL);
|
|
|
|
hook = g_hook_first_valid (&idle_hooks, FALSE);
|
|
|
|
if (hook)
|
|
{
|
|
last_idle = hook;
|
|
g_hook_ref (&idle_hooks, last_idle);
|
|
|
|
gtk_invoke_hook (&idle_hooks, last_idle);
|
|
|
|
gtk_finish_idles ();
|
|
}
|
|
}
|
|
|
|
static void
|
|
gtk_invoke_hook (GHookList *hook_list,
|
|
GHook *hook)
|
|
{
|
|
gboolean keep_alive;
|
|
|
|
if (hook->flags & GTK_HOOK_MARSHAL)
|
|
{
|
|
GtkArg args[1];
|
|
register GtkCallbackMarshal marshal;
|
|
|
|
keep_alive = FALSE;
|
|
args[0].name = NULL;
|
|
args[0].type = GTK_TYPE_BOOL;
|
|
GTK_VALUE_POINTER (args[0]) = &keep_alive;
|
|
marshal = hook->func;
|
|
marshal (NULL, hook->data, 0, args);
|
|
}
|
|
else
|
|
{
|
|
register GtkFunction func;
|
|
|
|
func = hook->func;
|
|
keep_alive = func (hook->data);
|
|
}
|
|
if (!keep_alive)
|
|
g_hook_destroy_link (hook_list, hook);
|
|
}
|
|
|
|
static gint
|
|
gtk_invoke_timeout_function (GtkTimeoutFunction *timeoutf)
|
|
{
|
|
if (!timeoutf->marshal)
|
|
return timeoutf->function (timeoutf->data);
|
|
else
|
|
{
|
|
GtkArg args[1];
|
|
gint ret_val = FALSE;
|
|
args[0].name = NULL;
|
|
args[0].type = GTK_TYPE_BOOL;
|
|
args[0].d.pointer_data = &ret_val;
|
|
timeoutf->marshal (NULL, timeoutf->data, 0, args);
|
|
return ret_val;
|
|
}
|
|
}
|
|
|
|
static void
|
|
gtk_handle_current_timeouts (guint32 the_time)
|
|
{
|
|
gint result;
|
|
GList *tmp_list;
|
|
GtkTimeoutFunction *timeoutf;
|
|
|
|
while (current_timeouts)
|
|
{
|
|
tmp_list = current_timeouts;
|
|
timeoutf = tmp_list->data;
|
|
|
|
current_timeouts = g_list_remove_link (current_timeouts, tmp_list);
|
|
if (running_timeouts)
|
|
{
|
|
running_timeouts->prev = tmp_list;
|
|
tmp_list->next = running_timeouts;
|
|
}
|
|
running_timeouts = tmp_list;
|
|
|
|
result = gtk_invoke_timeout_function (timeoutf);
|
|
|
|
running_timeouts = g_list_remove_link (running_timeouts, tmp_list);
|
|
timeoutf = tmp_list->data;
|
|
|
|
g_list_free_1 (tmp_list);
|
|
|
|
if (timeoutf)
|
|
{
|
|
if (!result)
|
|
{
|
|
gtk_timeout_destroy (timeoutf);
|
|
}
|
|
else
|
|
{
|
|
timeoutf->interval = timeoutf->originterval;
|
|
timeoutf->start = the_time;
|
|
gtk_timeout_insert (timeoutf);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
gtk_handle_timeouts (void)
|
|
{
|
|
guint32 the_time;
|
|
GList *tmp_list;
|
|
GList *tmp_list2;
|
|
GtkTimeoutFunction *timeoutf;
|
|
|
|
/* Caller must already have called gtk_handle_current_timeouts if
|
|
* necessary */
|
|
g_assert (current_timeouts == NULL);
|
|
|
|
if (timeout_functions)
|
|
{
|
|
the_time = gdk_time_get ();
|
|
|
|
tmp_list = timeout_functions;
|
|
while (tmp_list)
|
|
{
|
|
timeoutf = tmp_list->data;
|
|
|
|
if (timeoutf->interval <= (the_time - timeoutf->start))
|
|
{
|
|
tmp_list2 = tmp_list;
|
|
tmp_list = tmp_list->next;
|
|
|
|
timeout_functions = g_list_remove_link (timeout_functions, tmp_list2);
|
|
current_timeouts = g_list_concat (current_timeouts, tmp_list2);
|
|
}
|
|
else
|
|
{
|
|
timeoutf->interval -= (the_time - timeoutf->start);
|
|
timeoutf->start = the_time;
|
|
tmp_list = tmp_list->next;
|
|
}
|
|
}
|
|
|
|
if (current_timeouts)
|
|
gtk_handle_current_timeouts (the_time);
|
|
}
|
|
}
|
|
|
|
static void
|
|
gtk_quit_destroy (GtkQuitFunction *quitf)
|
|
{
|
|
if (quitf->destroy)
|
|
quitf->destroy (quitf->data);
|
|
g_mem_chunk_free (quit_mem_chunk, quitf);
|
|
}
|
|
|
|
static gint
|
|
gtk_quit_destructor (GtkObject **object_p)
|
|
{
|
|
if (*object_p)
|
|
gtk_object_destroy (*object_p);
|
|
g_free (object_p);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
void
|
|
gtk_quit_add_destroy (guint main_level,
|
|
GtkObject *object)
|
|
{
|
|
GtkObject **object_p;
|
|
|
|
g_return_if_fail (main_level > 0);
|
|
g_return_if_fail (object != NULL);
|
|
g_return_if_fail (GTK_IS_OBJECT (object));
|
|
|
|
object_p = g_new (GtkObject*, 1);
|
|
*object_p = object;
|
|
gtk_signal_connect (object,
|
|
"destroy",
|
|
GTK_SIGNAL_FUNC (gtk_widget_destroyed),
|
|
object_p);
|
|
gtk_quit_add (main_level, (GtkFunction) gtk_quit_destructor, object_p);
|
|
}
|
|
|
|
guint
|
|
gtk_quit_add (guint main_level,
|
|
GtkFunction function,
|
|
gpointer data)
|
|
{
|
|
return gtk_quit_add_full (main_level, function, NULL, data, NULL);
|
|
}
|
|
|
|
void
|
|
gtk_quit_remove (guint id)
|
|
{
|
|
GtkQuitFunction *quitf;
|
|
GList *tmp_list;
|
|
|
|
tmp_list = quit_functions;
|
|
while (tmp_list)
|
|
{
|
|
quitf = tmp_list->data;
|
|
|
|
if (quitf->id == id)
|
|
{
|
|
quit_functions = g_list_remove_link (quit_functions, tmp_list);
|
|
g_list_free (tmp_list);
|
|
gtk_quit_destroy (quitf);
|
|
|
|
return;
|
|
}
|
|
|
|
tmp_list = tmp_list->next;
|
|
}
|
|
}
|
|
|
|
void
|
|
gtk_quit_remove_by_data (gpointer data)
|
|
{
|
|
GtkQuitFunction *quitf;
|
|
GList *tmp_list;
|
|
|
|
tmp_list = quit_functions;
|
|
while (tmp_list)
|
|
{
|
|
quitf = tmp_list->data;
|
|
|
|
if (quitf->data == data)
|
|
{
|
|
quit_functions = g_list_remove_link (quit_functions, tmp_list);
|
|
g_list_free (tmp_list);
|
|
gtk_quit_destroy (quitf);
|
|
|
|
return;
|
|
}
|
|
|
|
tmp_list = tmp_list->next;
|
|
}
|
|
}
|
|
|
|
static void
|
|
gtk_invoke_input_function (GtkInputFunction *input,
|
|
gint source,
|
|
GdkInputCondition condition)
|
|
{
|
|
GtkArg args[3];
|
|
args[0].type = GTK_TYPE_INT;
|
|
args[0].name = NULL;
|
|
GTK_VALUE_INT(args[0]) = source;
|
|
args[1].type = GTK_TYPE_GDK_INPUT_CONDITION;
|
|
args[1].name = NULL;
|
|
GTK_VALUE_FLAGS(args[1]) = condition;
|
|
args[2].type = GTK_TYPE_NONE;
|
|
args[2].name = NULL;
|
|
|
|
input->callback (NULL, input->data, 2, args);
|
|
}
|
|
|
|
static void
|
|
gtk_destroy_input_function (GtkInputFunction *input)
|
|
{
|
|
if (input->destroy)
|
|
(input->destroy) (input->data);
|
|
g_free (input);
|
|
}
|
|
|
|
guint
|
|
gtk_input_add_full (gint source,
|
|
GdkInputCondition condition,
|
|
GdkInputFunction function,
|
|
GtkCallbackMarshal marshal,
|
|
gpointer data,
|
|
GtkDestroyNotify destroy)
|
|
{
|
|
if (marshal)
|
|
{
|
|
GtkInputFunction *input;
|
|
|
|
input = g_new (GtkInputFunction, 1);
|
|
input->callback = marshal;
|
|
input->data = data;
|
|
input->destroy = destroy;
|
|
|
|
return gdk_input_add_full (source,
|
|
condition,
|
|
(GdkInputFunction) gtk_invoke_input_function,
|
|
input,
|
|
(GdkDestroyNotify) gtk_destroy_input_function);
|
|
}
|
|
else
|
|
return gdk_input_add_full (source, condition, function, data, destroy);
|
|
}
|
|
|
|
void
|
|
gtk_input_remove (guint tag)
|
|
{
|
|
gdk_input_remove (tag);
|
|
}
|
|
|
|
GdkEvent *
|
|
gtk_get_current_event (void)
|
|
{
|
|
if (current_events)
|
|
return gdk_event_copy ((GdkEvent *) current_events->data);
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
GtkWidget*
|
|
gtk_get_event_widget (GdkEvent *event)
|
|
{
|
|
GtkWidget *widget;
|
|
|
|
widget = NULL;
|
|
if (event && event->any.window)
|
|
gdk_window_get_user_data (event->any.window, (void**) &widget);
|
|
|
|
return widget;
|
|
}
|
|
|
|
static void
|
|
gtk_exit_func (void)
|
|
{
|
|
if (gtk_initialized)
|
|
{
|
|
gtk_initialized = FALSE;
|
|
gtk_preview_uninit ();
|
|
}
|
|
}
|
|
|
|
|
|
/* We rely on some knowledge of how g_list_insert_sorted works to make
|
|
* sure that we insert after timeouts of equal interval
|
|
*/
|
|
static gint
|
|
gtk_timeout_compare (gconstpointer a, gconstpointer b)
|
|
{
|
|
return (((const GtkTimeoutFunction *)a)->interval <
|
|
((const GtkTimeoutFunction *)b)->interval)
|
|
? -1 : 1;
|
|
}
|
|
|
|
static void
|
|
gtk_timeout_insert (GtkTimeoutFunction *timeoutf)
|
|
{
|
|
g_assert (timeoutf != NULL);
|
|
|
|
/* Insert the timeout function appropriately.
|
|
* Appropriately meaning sort it into the list
|
|
* of timeout functions.
|
|
*/
|
|
timeout_functions = g_list_insert_sorted (timeout_functions, timeoutf,
|
|
gtk_timeout_compare);
|
|
}
|
|
|
|
static gint
|
|
gtk_quit_invoke_function (GtkQuitFunction *quitf)
|
|
{
|
|
if (!quitf->marshal)
|
|
return quitf->function (quitf->data);
|
|
else
|
|
{
|
|
GtkArg args[1];
|
|
gint ret_val = FALSE;
|
|
|
|
args[0].name = NULL;
|
|
args[0].type = GTK_TYPE_BOOL;
|
|
args[0].d.pointer_data = &ret_val;
|
|
((GtkCallbackMarshal) quitf->marshal) (NULL,
|
|
quitf->data,
|
|
0, args);
|
|
return ret_val;
|
|
}
|
|
}
|
|
|
|
static void
|
|
gtk_handle_timer (void)
|
|
{
|
|
GtkTimeoutFunction *timeoutf;
|
|
|
|
if (g_hook_first_valid (&idle_hooks, FALSE))
|
|
{
|
|
gdk_timer_set (0);
|
|
gdk_timer_enable ();
|
|
}
|
|
else if (timeout_functions)
|
|
{
|
|
timeoutf = timeout_functions->data;
|
|
gdk_timer_set (timeoutf->interval);
|
|
gdk_timer_enable ();
|
|
}
|
|
else
|
|
{
|
|
gdk_timer_set (0);
|
|
gdk_timer_disable ();
|
|
}
|
|
}
|
|
|
|
static void
|
|
gtk_propagate_event (GtkWidget *widget,
|
|
GdkEvent *event)
|
|
{
|
|
gint handled_event;
|
|
|
|
g_return_if_fail (widget != NULL);
|
|
g_return_if_fail (event != NULL);
|
|
|
|
handled_event = FALSE;
|
|
|
|
if ((event->type == GDK_KEY_PRESS) ||
|
|
(event->type == GDK_KEY_RELEASE))
|
|
{
|
|
/* Only send key events within Window widgets to the Window
|
|
* The Window widget will in turn pass the
|
|
* key event on to the currently focused widget
|
|
* for that window.
|
|
*/
|
|
GtkWidget *window;
|
|
|
|
window = gtk_widget_get_ancestor (widget, gtk_window_get_type ());
|
|
if (window)
|
|
{
|
|
if (GTK_WIDGET_IS_SENSITIVE (window))
|
|
gtk_widget_event (window, event);
|
|
|
|
handled_event = TRUE; /* don't send to widget */
|
|
}
|
|
}
|
|
|
|
/* Other events get propagated up the widget tree
|
|
* so that parents can see the button and motion
|
|
* events of the children.
|
|
*/
|
|
while (!handled_event && widget)
|
|
{
|
|
GtkWidget *tmp;
|
|
|
|
gtk_widget_ref (widget);
|
|
handled_event = !GTK_WIDGET_IS_SENSITIVE (widget) || gtk_widget_event (widget, event);
|
|
tmp = widget->parent;
|
|
gtk_widget_unref (widget);
|
|
widget = tmp;
|
|
}
|
|
}
|
|
|
|
|
|
#if 0
|
|
static void
|
|
gtk_error (gchar *str)
|
|
{
|
|
gtk_print (str);
|
|
}
|
|
|
|
static void
|
|
gtk_warning (gchar *str)
|
|
{
|
|
gtk_print (str);
|
|
}
|
|
|
|
static void
|
|
gtk_message (gchar *str)
|
|
{
|
|
gtk_print (str);
|
|
}
|
|
|
|
static void
|
|
gtk_print (gchar *str)
|
|
{
|
|
static GtkWidget *window = NULL;
|
|
static GtkWidget *text;
|
|
static int level = 0;
|
|
GtkWidget *box1;
|
|
GtkWidget *box2;
|
|
GtkWidget *table;
|
|
GtkWidget *hscrollbar;
|
|
GtkWidget *vscrollbar;
|
|
GtkWidget *separator;
|
|
GtkWidget *button;
|
|
|
|
if (level > 0)
|
|
{
|
|
fputs (str, stdout);
|
|
fflush (stdout);
|
|
return;
|
|
}
|
|
|
|
if (!window)
|
|
{
|
|
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
|
|
|
gtk_signal_connect (GTK_OBJECT (window), "destroy",
|
|
(GtkSignalFunc) gtk_widget_destroyed,
|
|
&window);
|
|
|
|
gtk_window_set_title (GTK_WINDOW (window), "Messages");
|
|
|
|
box1 = gtk_vbox_new (FALSE, 0);
|
|
gtk_container_add (GTK_CONTAINER (window), box1);
|
|
gtk_widget_show (box1);
|
|
|
|
|
|
box2 = gtk_vbox_new (FALSE, 10);
|
|
gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
|
|
gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
|
|
gtk_widget_show (box2);
|
|
|
|
|
|
table = gtk_table_new (2, 2, FALSE);
|
|
gtk_table_set_row_spacing (GTK_TABLE (table), 0, 2);
|
|
gtk_table_set_col_spacing (GTK_TABLE (table), 0, 2);
|
|
gtk_box_pack_start (GTK_BOX (box2), table, TRUE, TRUE, 0);
|
|
gtk_widget_show (table);
|
|
|
|
text = gtk_text_new (NULL, NULL);
|
|
gtk_text_set_editable (GTK_TEXT (text), FALSE);
|
|
gtk_table_attach_defaults (GTK_TABLE (table), text, 0, 1, 0, 1);
|
|
gtk_widget_show (text);
|
|
gtk_widget_realize (text);
|
|
|
|
hscrollbar = gtk_hscrollbar_new (GTK_TEXT (text)->hadj);
|
|
gtk_table_attach (GTK_TABLE (table), hscrollbar, 0, 1, 1, 2,
|
|
GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0);
|
|
gtk_widget_show (hscrollbar);
|
|
|
|
vscrollbar = gtk_vscrollbar_new (GTK_TEXT (text)->vadj);
|
|
gtk_table_attach (GTK_TABLE (table), vscrollbar, 1, 2, 0, 1,
|
|
GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
|
|
gtk_widget_show (vscrollbar);
|
|
|
|
separator = gtk_hseparator_new ();
|
|
gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0);
|
|
gtk_widget_show (separator);
|
|
|
|
|
|
box2 = gtk_vbox_new (FALSE, 10);
|
|
gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
|
|
gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0);
|
|
gtk_widget_show (box2);
|
|
|
|
|
|
button = gtk_button_new_with_label ("close");
|
|
gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
|
|
(GtkSignalFunc) gtk_widget_hide,
|
|
GTK_OBJECT (window));
|
|
gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
|
|
GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
|
|
gtk_widget_grab_default (button);
|
|
gtk_widget_show (button);
|
|
}
|
|
|
|
level += 1;
|
|
gtk_text_insert (GTK_TEXT (text), NULL, NULL, NULL, str, -1);
|
|
level -= 1;
|
|
|
|
if (!GTK_WIDGET_VISIBLE (window))
|
|
gtk_widget_show (window);
|
|
}
|
|
#endif
|