Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorMarco Pesenti Gritti <marco@localhost.localdomain>2006-10-12 10:47:17 (GMT)
committer Marco Pesenti Gritti <marco@localhost.localdomain>2006-10-12 10:47:17 (GMT)
commit62a46ff92b234d07437f9f36efea576996eb84e2 (patch)
tree8bcb898523a5c907e38eb4fc006a2e31d814cef8 /lib
parent5cc6ee3235b6b1301f14f7aae9d1a36abef45557 (diff)
Create a private sugar lib and put our extensions there.
Diffstat (limited to 'lib')
-rw-r--r--lib/Makefile.am1
-rw-r--r--lib/__init__.py0
-rw-r--r--lib/python/Makefile.am33
-rw-r--r--lib/python/_sugar.c365
-rw-r--r--lib/python/_sugar.defs66
-rw-r--r--lib/python/_sugar.override19
-rw-r--r--lib/python/_sugarmodule.c27
-rw-r--r--lib/src/Makefile.am14
-rw-r--r--lib/src/eggaccelerators.c702
-rw-r--r--lib/src/eggaccelerators.h89
-rw-r--r--lib/src/gecko-browser.cpp78
-rw-r--r--lib/src/gecko-browser.h54
-rw-r--r--lib/src/sugar-key-grabber.c249
-rw-r--r--lib/src/sugar-key-grabber.h44
-rw-r--r--lib/threadframe/GNUmakefile.mingw218
-rw-r--r--lib/threadframe/Makefile.am6
-rw-r--r--lib/threadframe/README34
-rw-r--r--lib/threadframe/sample.txt37
-rw-r--r--lib/threadframe/setup.py21
-rw-r--r--lib/threadframe/test.py57
-rw-r--r--lib/threadframe/threadframe.def3
-rw-r--r--lib/threadframe/threadframemodule.c111
22 files changed, 2028 insertions, 0 deletions
diff --git a/lib/Makefile.am b/lib/Makefile.am
new file mode 100644
index 0000000..055aa29
--- /dev/null
+++ b/lib/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = src python
diff --git a/lib/__init__.py b/lib/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/lib/__init__.py
diff --git a/lib/python/Makefile.am b/lib/python/Makefile.am
new file mode 100644
index 0000000..eb6b85c
--- /dev/null
+++ b/lib/python/Makefile.am
@@ -0,0 +1,33 @@
+INCLUDES = \
+ $(PYTHON_INCLUDES) \
+ $(PYGTK_CFLAGS) \
+ $(LIB_CFLAGS) \
+ -I $(top_srcdir)/lib/src
+
+pkgpyexecdir = $(pythondir)
+
+pkgpyexec_LTLIBRARIES = _sugar.la
+
+_sugar_la_LDFLAGS = -module -avoid-version -R$(MOZILLA_HOME)
+_sugar_la_LIBADD = \
+ $(LIB_LIBS) \
+ $(top_builddir)/lib/src/libsugarprivate.la
+
+_sugar_la_SOURCES = \
+ _sugarmodule.c
+
+nodist__sugar_la_SOURCES = _sugar.c
+
+_sugar.c: _sugar.defs _sugar.override
+
+CLEANFILES = _sugar.c
+EXTRA_DIST = _sugar.override _sugar.defs
+
+.defs.c:
+ (cd $(srcdir)\
+ && $(PYGTK_CODEGEN) \
+ --register $(GNOMEPYTHONEXTRAS_DEFSDIR)/gtkmozembed.defs \
+ --override $*.override \
+ --prefix py$* $*.defs) > gen-$*.c \
+ && cp gen-$*.c $*.c \
+ && rm -f gen-$*.c
diff --git a/lib/python/_sugar.c b/lib/python/_sugar.c
new file mode 100644
index 0000000..1938322
--- /dev/null
+++ b/lib/python/_sugar.c
@@ -0,0 +1,365 @@
+/* -- THIS FILE IS GENERATED - DO NOT EDIT *//* -*- Mode: C; c-basic-offset: 4 -*- */
+
+#include <Python.h>
+
+
+
+#line 4 "_sugar.override"
+#include <Python.h>
+
+#include "pygobject.h"
+#include "gecko-browser.h"
+#include "sugar-key-grabber.h"
+
+#line 15 "_sugar.c"
+
+
+/* ---------- types from other modules ---------- */
+static PyTypeObject *_PyGObject_Type;
+#define PyGObject_Type (*_PyGObject_Type)
+static PyTypeObject *_PyGtkMozEmbed_Type;
+#define PyGtkMozEmbed_Type (*_PyGtkMozEmbed_Type)
+
+
+/* ---------- forward type declarations ---------- */
+PyTypeObject G_GNUC_INTERNAL PyGeckoBrowser_Type;
+PyTypeObject G_GNUC_INTERNAL PySugarKeyGrabber_Type;
+
+#line 29 "_sugar.c"
+
+
+
+/* ----------- GeckoBrowser ----------- */
+
+static int
+_wrap_gecko_browser_new(PyGObject *self, PyObject *args, PyObject *kwargs)
+{
+ static char* kwlist[] = { NULL };
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs,
+ ":gecko.Browser.__init__",
+ kwlist))
+ return -1;
+
+ pygobject_constructv(self, 0, NULL);
+ if (!self->obj) {
+ PyErr_SetString(
+ PyExc_RuntimeError,
+ "could not create gecko.Browser object");
+ return -1;
+ }
+ return 0;
+}
+
+static PyObject *
+_wrap_gecko_browser_create_window(PyGObject *self)
+{
+ GeckoBrowser *ret;
+
+
+ ret = gecko_browser_create_window(GECKO_BROWSER(self->obj));
+
+ /* pygobject_new handles NULL checking */
+ return pygobject_new((GObject *)ret);
+}
+
+static PyObject *
+_wrap_GeckoBrowser__do_create_window(PyObject *cls, PyObject *args, PyObject *kwargs)
+{
+ gpointer klass;
+ static char *kwlist[] = { "self", NULL };
+ PyGObject *self;
+ GeckoBrowser *ret;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs,"O!:GeckoBrowser.create_window", kwlist, &PyGeckoBrowser_Type, &self))
+ return NULL;
+ klass = g_type_class_ref(pyg_type_from_object(cls));
+ if (GECKO_BROWSER_CLASS(klass)->create_window)
+ ret = GECKO_BROWSER_CLASS(klass)->create_window(GECKO_BROWSER(self->obj));
+ else {
+ PyErr_SetString(PyExc_NotImplementedError, "virtual method GeckoBrowser.create_window not implemented");
+ g_type_class_unref(klass);
+ return NULL;
+ }
+ g_type_class_unref(klass);
+ /* pygobject_new handles NULL checking */
+ return pygobject_new((GObject *)ret);
+}
+
+static const PyMethodDef _PyGeckoBrowser_methods[] = {
+ { "create_window", (PyCFunction)_wrap_gecko_browser_create_window, METH_NOARGS,
+ NULL },
+ { "do_create_window", (PyCFunction)_wrap_GeckoBrowser__do_create_window, METH_VARARGS|METH_KEYWORDS|METH_CLASS,
+ NULL },
+ { NULL, NULL, 0, NULL }
+};
+
+PyTypeObject G_GNUC_INTERNAL PyGeckoBrowser_Type = {
+ PyObject_HEAD_INIT(NULL)
+ 0, /* ob_size */
+ "gecko.Browser", /* tp_name */
+ sizeof(PyGObject), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ /* methods */
+ (destructor)0, /* tp_dealloc */
+ (printfunc)0, /* tp_print */
+ (getattrfunc)0, /* tp_getattr */
+ (setattrfunc)0, /* tp_setattr */
+ (cmpfunc)0, /* tp_compare */
+ (reprfunc)0, /* tp_repr */
+ (PyNumberMethods*)0, /* tp_as_number */
+ (PySequenceMethods*)0, /* tp_as_sequence */
+ (PyMappingMethods*)0, /* tp_as_mapping */
+ (hashfunc)0, /* tp_hash */
+ (ternaryfunc)0, /* tp_call */
+ (reprfunc)0, /* tp_str */
+ (getattrofunc)0, /* tp_getattro */
+ (setattrofunc)0, /* tp_setattro */
+ (PyBufferProcs*)0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ NULL, /* Documentation string */
+ (traverseproc)0, /* tp_traverse */
+ (inquiry)0, /* tp_clear */
+ (richcmpfunc)0, /* tp_richcompare */
+ offsetof(PyGObject, weakreflist), /* tp_weaklistoffset */
+ (getiterfunc)0, /* tp_iter */
+ (iternextfunc)0, /* tp_iternext */
+ (struct PyMethodDef*)_PyGeckoBrowser_methods, /* tp_methods */
+ (struct PyMemberDef*)0, /* tp_members */
+ (struct PyGetSetDef*)0, /* tp_getset */
+ NULL, /* tp_base */
+ NULL, /* tp_dict */
+ (descrgetfunc)0, /* tp_descr_get */
+ (descrsetfunc)0, /* tp_descr_set */
+ offsetof(PyGObject, inst_dict), /* tp_dictoffset */
+ (initproc)_wrap_gecko_browser_new, /* tp_init */
+ (allocfunc)0, /* tp_alloc */
+ (newfunc)0, /* tp_new */
+ (freefunc)0, /* tp_free */
+ (inquiry)0 /* tp_is_gc */
+};
+
+static GeckoBrowser*
+_wrap_GeckoBrowser__proxy_do_create_window(GeckoBrowser *self)
+{
+ PyGILState_STATE __py_state;
+ PyObject *py_self;
+ GeckoBrowser* retval;
+ PyObject *py_retval;
+ PyObject *py_method;
+
+ __py_state = pyg_gil_state_ensure();
+ py_self = pygobject_new((GObject *) self);
+ if (!py_self) {
+ if (PyErr_Occurred())
+ PyErr_Print();
+ pyg_gil_state_release(__py_state);
+ return NULL;
+ }
+
+
+ py_method = PyObject_GetAttrString(py_self, "do_create_window");
+ if (!py_method) {
+ if (PyErr_Occurred())
+ PyErr_Print();
+ Py_DECREF(py_self);
+ pyg_gil_state_release(__py_state);
+ return NULL;
+ }
+ py_retval = PyObject_CallObject(py_method, NULL);
+ if (!py_retval) {
+ if (PyErr_Occurred())
+ PyErr_Print();
+ Py_DECREF(py_method);
+ Py_DECREF(py_self);
+ pyg_gil_state_release(__py_state);
+ return NULL;
+ }
+ if (!PyObject_TypeCheck(py_retval, &PyGObject_Type)) {
+ PyErr_SetString(PyExc_TypeError, "retval should be a GObject");
+ PyErr_Print();
+ Py_DECREF(py_retval);
+ Py_DECREF(py_method);
+ Py_DECREF(py_self);
+ pyg_gil_state_release(__py_state);
+ return NULL;
+ }
+ retval = (GeckoBrowser*) pygobject_get(py_retval);
+ g_object_ref((GObject *) retval);
+
+
+ Py_DECREF(py_retval);
+ Py_DECREF(py_method);
+ Py_DECREF(py_self);
+ pyg_gil_state_release(__py_state);
+
+ return retval;
+}
+
+static int
+__GeckoBrowser_class_init(gpointer gclass, PyTypeObject *pyclass)
+{
+ PyObject *o;
+ GeckoBrowserClass *klass = GECKO_BROWSER_CLASS(gclass);
+ PyObject *gsignals = PyDict_GetItemString(pyclass->tp_dict, "__gsignals__");
+
+ o = PyObject_GetAttrString((PyObject *) pyclass, "do_create_window");
+ if (o == NULL)
+ PyErr_Clear();
+ else {
+ if (!PyObject_TypeCheck(o, &PyCFunction_Type)
+ && !(gsignals && PyDict_GetItemString(gsignals, "create_window")))
+ klass->create_window = _wrap_GeckoBrowser__proxy_do_create_window;
+ Py_DECREF(o);
+ }
+ return 0;
+}
+
+
+/* ----------- SugarKeyGrabber ----------- */
+
+static int
+_wrap_sugar_key_grabber_new(PyGObject *self, PyObject *args, PyObject *kwargs)
+{
+ static char* kwlist[] = { NULL };
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs,
+ ":gecko.KeyGrabber.__init__",
+ kwlist))
+ return -1;
+
+ pygobject_constructv(self, 0, NULL);
+ if (!self->obj) {
+ PyErr_SetString(
+ PyExc_RuntimeError,
+ "could not create gecko.KeyGrabber object");
+ return -1;
+ }
+ return 0;
+}
+
+static PyObject *
+_wrap_sugar_key_grabber_grab(PyGObject *self, PyObject *args, PyObject *kwargs)
+{
+ static char *kwlist[] = { "address", NULL };
+ char *address;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs,"s:SugarKeyGrabber.grab", kwlist, &address))
+ return NULL;
+
+ sugar_key_grabber_grab(SUGAR_KEY_GRABBER(self->obj), address);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static const PyMethodDef _PySugarKeyGrabber_methods[] = {
+ { "grab", (PyCFunction)_wrap_sugar_key_grabber_grab, METH_VARARGS|METH_KEYWORDS,
+ NULL },
+ { NULL, NULL, 0, NULL }
+};
+
+PyTypeObject G_GNUC_INTERNAL PySugarKeyGrabber_Type = {
+ PyObject_HEAD_INIT(NULL)
+ 0, /* ob_size */
+ "gecko.KeyGrabber", /* tp_name */
+ sizeof(PyGObject), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ /* methods */
+ (destructor)0, /* tp_dealloc */
+ (printfunc)0, /* tp_print */
+ (getattrfunc)0, /* tp_getattr */
+ (setattrfunc)0, /* tp_setattr */
+ (cmpfunc)0, /* tp_compare */
+ (reprfunc)0, /* tp_repr */
+ (PyNumberMethods*)0, /* tp_as_number */
+ (PySequenceMethods*)0, /* tp_as_sequence */
+ (PyMappingMethods*)0, /* tp_as_mapping */
+ (hashfunc)0, /* tp_hash */
+ (ternaryfunc)0, /* tp_call */
+ (reprfunc)0, /* tp_str */
+ (getattrofunc)0, /* tp_getattro */
+ (setattrofunc)0, /* tp_setattro */
+ (PyBufferProcs*)0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ NULL, /* Documentation string */
+ (traverseproc)0, /* tp_traverse */
+ (inquiry)0, /* tp_clear */
+ (richcmpfunc)0, /* tp_richcompare */
+ offsetof(PyGObject, weakreflist), /* tp_weaklistoffset */
+ (getiterfunc)0, /* tp_iter */
+ (iternextfunc)0, /* tp_iternext */
+ (struct PyMethodDef*)_PySugarKeyGrabber_methods, /* tp_methods */
+ (struct PyMemberDef*)0, /* tp_members */
+ (struct PyGetSetDef*)0, /* tp_getset */
+ NULL, /* tp_base */
+ NULL, /* tp_dict */
+ (descrgetfunc)0, /* tp_descr_get */
+ (descrsetfunc)0, /* tp_descr_set */
+ offsetof(PyGObject, inst_dict), /* tp_dictoffset */
+ (initproc)_wrap_sugar_key_grabber_new, /* tp_init */
+ (allocfunc)0, /* tp_alloc */
+ (newfunc)0, /* tp_new */
+ (freefunc)0, /* tp_free */
+ (inquiry)0 /* tp_is_gc */
+};
+
+
+
+/* ----------- functions ----------- */
+
+static PyObject *
+_wrap_gecko_browser_startup(PyObject *self)
+{
+
+ gecko_browser_startup();
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+const PyMethodDef py_sugar_functions[] = {
+ { "startup_browser", (PyCFunction)_wrap_gecko_browser_startup, METH_NOARGS,
+ NULL },
+ { NULL, NULL, 0, NULL }
+};
+
+/* initialise stuff extension classes */
+void
+py_sugar_register_classes(PyObject *d)
+{
+ PyObject *module;
+
+ if ((module = PyImport_ImportModule("gobject")) != NULL) {
+ _PyGObject_Type = (PyTypeObject *)PyObject_GetAttrString(module, "GObject");
+ if (_PyGObject_Type == NULL) {
+ PyErr_SetString(PyExc_ImportError,
+ "cannot import name GObject from gobject");
+ return ;
+ }
+ } else {
+ PyErr_SetString(PyExc_ImportError,
+ "could not import gobject");
+ return ;
+ }
+ if ((module = PyImport_ImportModule("gtkmozembed")) != NULL) {
+ _PyGtkMozEmbed_Type = (PyTypeObject *)PyObject_GetAttrString(module, "MozEmbed");
+ if (_PyGtkMozEmbed_Type == NULL) {
+ PyErr_SetString(PyExc_ImportError,
+ "cannot import name MozEmbed from gtkmozembed");
+ return ;
+ }
+ } else {
+ PyErr_SetString(PyExc_ImportError,
+ "could not import gtkmozembed");
+ return ;
+ }
+
+
+#line 360 "_sugar.c"
+ pygobject_register_class(d, "GeckoBrowser", GECKO_TYPE_BROWSER, &PyGeckoBrowser_Type, Py_BuildValue("(O)", &PyGtkMozEmbed_Type));
+ pyg_set_object_has_new_constructor(GECKO_TYPE_BROWSER);
+ pyg_register_class_init(GECKO_TYPE_BROWSER, __GeckoBrowser_class_init);
+ pygobject_register_class(d, "SugarKeyGrabber", SUGAR_TYPE_KEY_GRABBER, &PySugarKeyGrabber_Type, Py_BuildValue("(O)", &PyGObject_Type));
+ pyg_set_object_has_new_constructor(SUGAR_TYPE_KEY_GRABBER);
+}
diff --git a/lib/python/_sugar.defs b/lib/python/_sugar.defs
new file mode 100644
index 0000000..011bf71
--- /dev/null
+++ b/lib/python/_sugar.defs
@@ -0,0 +1,66 @@
+;; -*- scheme -*-
+; object definitions ...
+(define-object Browser
+ (in-module "Gecko")
+ (parent "GtkMozEmbed")
+ (c-name "GeckoBrowser")
+ (gtype-id "GECKO_TYPE_BROWSER")
+)
+
+;; Enumerations and flags ...
+
+
+;; From gecko-browser.h
+
+(define-function get_type
+ (c-name "gecko_browser_get_type")
+ (return-type "GType")
+)
+
+(define-function startup_browser
+ (c-name "gecko_browser_startup")
+ (return-type "none")
+)
+
+(define-function new
+ (c-name "gecko_browser_new")
+ (is-constructor-of "GeckoBrowser")
+ (return-type "GeckoBrowser*")
+)
+
+(define-method create_window
+ (of-object "GeckoBrowser")
+ (c-name "gecko_browser_create_window")
+ (return-type "GeckoBrowser*")
+)
+
+(define-virtual create_window
+ (of-object "GeckoBrowser")
+ (return-type "GeckoBrowser*")
+)
+(define-object KeyGrabber
+ (in-module "globalkeys")
+ (parent "GObject")
+ (c-name "SugarKeyGrabber")
+ (gtype-id "SUGAR_TYPE_KEY_GRABBER")
+)
+
+(define-function sugar_key_grabber_get_type
+ (c-name "sugar_key_grabber_get_type")
+ (return-type "GType")
+)
+
+(define-function sugar_key_grabber_new
+ (c-name "sugar_key_grabber_new")
+ (is-constructor-of "SugarKeyGrabber")
+ (return-type "GObject*")
+)
+
+(define-method grab
+ (of-object "SugarKeyGrabber")
+ (c-name "sugar_key_grabber_grab")
+ (return-type "none")
+ (parameters
+ '("const-char*" "address")
+ )
+)
diff --git a/lib/python/_sugar.override b/lib/python/_sugar.override
new file mode 100644
index 0000000..e439186
--- /dev/null
+++ b/lib/python/_sugar.override
@@ -0,0 +1,19 @@
+/* -*- Mode: C; c-basic-offset: 4 -*- */
+%%
+headers
+#include <Python.h>
+
+#include "pygobject.h"
+#include "gecko-browser.h"
+#include "sugar-key-grabber.h"
+
+%%
+modulename gecko
+%%
+import gobject.GObject as PyGObject_Type
+import gtkmozembed.MozEmbed as PyGtkMozEmbed_Type
+%%
+ignore-glob
+ *_get_type
+ _*
+%%
diff --git a/lib/python/_sugarmodule.c b/lib/python/_sugarmodule.c
new file mode 100644
index 0000000..4d8511b
--- /dev/null
+++ b/lib/python/_sugarmodule.c
@@ -0,0 +1,27 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+/* include this first, before NO_IMPORT_PYGOBJECT is defined */
+#include <pygobject.h>
+
+void py_sugar_register_classes (PyObject *d);
+
+extern PyMethodDef py_sugar_functions[];
+
+DL_EXPORT(void)
+init_sugar(void)
+{
+ PyObject *m, *d;
+
+ init_pygobject ();
+
+ m = Py_InitModule ("_sugar", py_sugar_functions);
+ d = PyModule_GetDict (m);
+
+ py_sugar_register_classes (d);
+
+ if (PyErr_Occurred ()) {
+ Py_FatalError ("can't initialise module globalkeys");
+ }
+}
diff --git a/lib/src/Makefile.am b/lib/src/Makefile.am
new file mode 100644
index 0000000..57c6a32
--- /dev/null
+++ b/lib/src/Makefile.am
@@ -0,0 +1,14 @@
+INCLUDES = \
+ $(LIB_CFLAGS)
+
+noinst_LTLIBRARIES = libsugarprivate.la
+
+libsugarprivate_la_LIBADD = $(GECKO_LIBS)
+
+libsugarprivate_la_SOURCES = \
+ eggaccelerators.h \
+ eggaccelerators.c \
+ gecko-browser.h \
+ gecko-browser.cpp \
+ sugar-key-grabber.h \
+ sugar-key-grabber.c
diff --git a/lib/src/eggaccelerators.c b/lib/src/eggaccelerators.c
new file mode 100644
index 0000000..0a39d51
--- /dev/null
+++ b/lib/src/eggaccelerators.c
@@ -0,0 +1,702 @@
+/* eggaccelerators.c
+ * Copyright (C) 2002 Red Hat, Inc.; Copyright 1998, 2001 Tim Janik
+ * Developed by Havoc Pennington, Tim Janik
+ *
+ * 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 "eggaccelerators.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <gdk/gdkx.h>
+#include <gdk/gdkkeysyms.h>
+
+enum
+{
+ EGG_MODMAP_ENTRY_SHIFT = 0,
+ EGG_MODMAP_ENTRY_LOCK = 1,
+ EGG_MODMAP_ENTRY_CONTROL = 2,
+ EGG_MODMAP_ENTRY_MOD1 = 3,
+ EGG_MODMAP_ENTRY_MOD2 = 4,
+ EGG_MODMAP_ENTRY_MOD3 = 5,
+ EGG_MODMAP_ENTRY_MOD4 = 6,
+ EGG_MODMAP_ENTRY_MOD5 = 7,
+ EGG_MODMAP_ENTRY_LAST = 8
+};
+
+#define MODMAP_ENTRY_TO_MODIFIER(x) (1 << (x))
+
+typedef struct
+{
+ EggVirtualModifierType mapping[EGG_MODMAP_ENTRY_LAST];
+
+} EggModmap;
+
+const EggModmap* egg_keymap_get_modmap (GdkKeymap *keymap);
+
+static inline gboolean
+is_alt (const gchar *string)
+{
+ return ((string[0] == '<') &&
+ (string[1] == 'a' || string[1] == 'A') &&
+ (string[2] == 'l' || string[2] == 'L') &&
+ (string[3] == 't' || string[3] == 'T') &&
+ (string[4] == '>'));
+}
+
+static inline gboolean
+is_ctl (const gchar *string)
+{
+ return ((string[0] == '<') &&
+ (string[1] == 'c' || string[1] == 'C') &&
+ (string[2] == 't' || string[2] == 'T') &&
+ (string[3] == 'l' || string[3] == 'L') &&
+ (string[4] == '>'));
+}
+
+static inline gboolean
+is_modx (const gchar *string)
+{
+ return ((string[0] == '<') &&
+ (string[1] == 'm' || string[1] == 'M') &&
+ (string[2] == 'o' || string[2] == 'O') &&
+ (string[3] == 'd' || string[3] == 'D') &&
+ (string[4] >= '1' && string[4] <= '5') &&
+ (string[5] == '>'));
+}
+
+static inline gboolean
+is_ctrl (const gchar *string)
+{
+ return ((string[0] == '<') &&
+ (string[1] == 'c' || string[1] == 'C') &&
+ (string[2] == 't' || string[2] == 'T') &&
+ (string[3] == 'r' || string[3] == 'R') &&
+ (string[4] == 'l' || string[4] == 'L') &&
+ (string[5] == '>'));
+}
+
+static inline gboolean
+is_shft (const gchar *string)
+{
+ return ((string[0] == '<') &&
+ (string[1] == 's' || string[1] == 'S') &&
+ (string[2] == 'h' || string[2] == 'H') &&
+ (string[3] == 'f' || string[3] == 'F') &&
+ (string[4] == 't' || string[4] == 'T') &&
+ (string[5] == '>'));
+}
+
+static inline gboolean
+is_shift (const gchar *string)
+{
+ return ((string[0] == '<') &&
+ (string[1] == 's' || string[1] == 'S') &&
+ (string[2] == 'h' || string[2] == 'H') &&
+ (string[3] == 'i' || string[3] == 'I') &&
+ (string[4] == 'f' || string[4] == 'F') &&
+ (string[5] == 't' || string[5] == 'T') &&
+ (string[6] == '>'));
+}
+
+static inline gboolean
+is_control (const gchar *string)
+{
+ return ((string[0] == '<') &&
+ (string[1] == 'c' || string[1] == 'C') &&
+ (string[2] == 'o' || string[2] == 'O') &&
+ (string[3] == 'n' || string[3] == 'N') &&
+ (string[4] == 't' || string[4] == 'T') &&
+ (string[5] == 'r' || string[5] == 'R') &&
+ (string[6] == 'o' || string[6] == 'O') &&
+ (string[7] == 'l' || string[7] == 'L') &&
+ (string[8] == '>'));
+}
+
+static inline gboolean
+is_release (const gchar *string)
+{
+ return ((string[0] == '<') &&
+ (string[1] == 'r' || string[1] == 'R') &&
+ (string[2] == 'e' || string[2] == 'E') &&
+ (string[3] == 'l' || string[3] == 'L') &&
+ (string[4] == 'e' || string[4] == 'E') &&
+ (string[5] == 'a' || string[5] == 'A') &&
+ (string[6] == 's' || string[6] == 'S') &&
+ (string[7] == 'e' || string[7] == 'E') &&
+ (string[8] == '>'));
+}
+
+static inline gboolean
+is_meta (const gchar *string)
+{
+ return ((string[0] == '<') &&
+ (string[1] == 'm' || string[1] == 'M') &&
+ (string[2] == 'e' || string[2] == 'E') &&
+ (string[3] == 't' || string[3] == 'T') &&
+ (string[4] == 'a' || string[4] == 'A') &&
+ (string[5] == '>'));
+}
+
+static inline gboolean
+is_super (const gchar *string)
+{
+ return ((string[0] == '<') &&
+ (string[1] == 's' || string[1] == 'S') &&
+ (string[2] == 'u' || string[2] == 'U') &&
+ (string[3] == 'p' || string[3] == 'P') &&
+ (string[4] == 'e' || string[4] == 'E') &&
+ (string[5] == 'r' || string[5] == 'R') &&
+ (string[6] == '>'));
+}
+
+static inline gboolean
+is_hyper (const gchar *string)
+{
+ return ((string[0] == '<') &&
+ (string[1] == 'h' || string[1] == 'H') &&
+ (string[2] == 'y' || string[2] == 'Y') &&
+ (string[3] == 'p' || string[3] == 'P') &&
+ (string[4] == 'e' || string[4] == 'E') &&
+ (string[5] == 'r' || string[5] == 'R') &&
+ (string[6] == '>'));
+}
+
+static inline gboolean
+is_keycode (const gchar *string)
+{
+ return ((string[0] == '0') &&
+ (string[1] == 'x'));
+}
+
+/**
+ * egg_accelerator_parse_virtual:
+ * @accelerator: string representing an accelerator
+ * @accelerator_key: return location for accelerator keyval
+ * @accelerator_mods: return location for accelerator modifier mask
+ *
+ * Parses a string representing a virtual accelerator. The format
+ * looks like "&lt;Control&gt;a" or "&lt;Shift&gt;&lt;Alt&gt;F1" or
+ * "&lt;Release&gt;z" (the last one is for key release). The parser
+ * is fairly liberal and allows lower or upper case, and also
+ * abbreviations such as "&lt;Ctl&gt;" and "&lt;Ctrl&gt;".
+ *
+ * If the parse fails, @accelerator_key and @accelerator_mods will
+ * be set to 0 (zero) and %FALSE will be returned. If the string contains
+ * only modifiers, @accelerator_key will be set to 0 but %TRUE will be
+ * returned.
+ *
+ * The virtual vs. concrete accelerator distinction is a relic of
+ * how the X Window System works; there are modifiers Mod2-Mod5 that
+ * can represent various keyboard keys (numlock, meta, hyper, etc.),
+ * the virtual modifier represents the keyboard key, the concrete
+ * modifier the actual Mod2-Mod5 bits in the key press event.
+ *
+ * Returns: %TRUE on success.
+ */
+gboolean
+egg_accelerator_parse_virtual (const gchar *accelerator,
+ guint *accelerator_key,
+ guint *keycode,
+ EggVirtualModifierType *accelerator_mods)
+{
+ guint keyval;
+ GdkModifierType mods;
+ gint len;
+ gboolean bad_keyval;
+
+ if (accelerator_key)
+ *accelerator_key = 0;
+ if (accelerator_mods)
+ *accelerator_mods = 0;
+ if (keycode)
+ *keycode = 0;
+
+ g_return_val_if_fail (accelerator != NULL, FALSE);
+
+ bad_keyval = FALSE;
+
+ keyval = 0;
+ mods = 0;
+ len = strlen (accelerator);
+ while (len)
+ {
+ if (*accelerator == '<')
+ {
+ if (len >= 9 && is_release (accelerator))
+ {
+ accelerator += 9;
+ len -= 9;
+ mods |= EGG_VIRTUAL_RELEASE_MASK;
+ }
+ else if (len >= 9 && is_control (accelerator))
+ {
+ accelerator += 9;
+ len -= 9;
+ mods |= EGG_VIRTUAL_CONTROL_MASK;
+ }
+ else if (len >= 7 && is_shift (accelerator))
+ {
+ accelerator += 7;
+ len -= 7;
+ mods |= EGG_VIRTUAL_SHIFT_MASK;
+ }
+ else if (len >= 6 && is_shft (accelerator))
+ {
+ accelerator += 6;
+ len -= 6;
+ mods |= EGG_VIRTUAL_SHIFT_MASK;
+ }
+ else if (len >= 6 && is_ctrl (accelerator))
+ {
+ accelerator += 6;
+ len -= 6;
+ mods |= EGG_VIRTUAL_CONTROL_MASK;
+ }
+ else if (len >= 6 && is_modx (accelerator))
+ {
+ static const guint mod_vals[] = {
+ EGG_VIRTUAL_ALT_MASK, EGG_VIRTUAL_MOD2_MASK, EGG_VIRTUAL_MOD3_MASK,
+ EGG_VIRTUAL_MOD4_MASK, EGG_VIRTUAL_MOD5_MASK
+ };
+
+ len -= 6;
+ accelerator += 4;
+ mods |= mod_vals[*accelerator - '1'];
+ accelerator += 2;
+ }
+ else if (len >= 5 && is_ctl (accelerator))
+ {
+ accelerator += 5;
+ len -= 5;
+ mods |= EGG_VIRTUAL_CONTROL_MASK;
+ }
+ else if (len >= 5 && is_alt (accelerator))
+ {
+ accelerator += 5;
+ len -= 5;
+ mods |= EGG_VIRTUAL_ALT_MASK;
+ }
+ else if (len >= 6 && is_meta (accelerator))
+ {
+ accelerator += 6;
+ len -= 6;
+ mods |= EGG_VIRTUAL_META_MASK;
+ }
+ else if (len >= 7 && is_hyper (accelerator))
+ {
+ accelerator += 7;
+ len -= 7;
+ mods |= EGG_VIRTUAL_HYPER_MASK;
+ }
+ else if (len >= 7 && is_super (accelerator))
+ {
+ accelerator += 7;
+ len -= 7;
+ mods |= EGG_VIRTUAL_SUPER_MASK;
+ }
+ else
+ {
+ gchar last_ch;
+
+ last_ch = *accelerator;
+ while (last_ch && last_ch != '>')
+ {
+ last_ch = *accelerator;
+ accelerator += 1;
+ len -= 1;
+ }
+ }
+ }
+ else
+ {
+ keyval = gdk_keyval_from_name (accelerator);
+
+ if (keyval == 0)
+ {
+ /* If keyval is 0, than maybe it's a keycode. Check for 0x## */
+ if (len >= 4 && is_keycode (accelerator))
+ {
+ char keystring[5];
+ gchar *endptr;
+ gint tmp_keycode;
+
+ memcpy (keystring, accelerator, 4);
+ keystring [4] = '\000';
+
+ tmp_keycode = strtol (keystring, &endptr, 16);
+
+ if (endptr == NULL || *endptr != '\000')
+ {
+ bad_keyval = TRUE;
+ }
+ else if (keycode != NULL)
+ {
+ *keycode = tmp_keycode;
+ /* 0x00 is an invalid keycode too. */
+ if (*keycode == 0)
+ bad_keyval = TRUE;
+ }
+ }
+ } else if (keycode != NULL)
+ *keycode = XKeysymToKeycode (GDK_DISPLAY(), keyval);
+
+ accelerator += len;
+ len -= len;
+ }
+ }
+
+ if (accelerator_key)
+ *accelerator_key = gdk_keyval_to_lower (keyval);
+ if (accelerator_mods)
+ *accelerator_mods = mods;
+
+ return !bad_keyval;
+}
+
+
+/**
+ * egg_virtual_accelerator_name:
+ * @accelerator_key: accelerator keyval
+ * @accelerator_mods: accelerator modifier mask
+ * @returns: a newly-allocated accelerator name
+ *
+ * Converts an accelerator keyval and modifier mask
+ * into a string parseable by egg_accelerator_parse_virtual().
+ * For example, if you pass in #GDK_q and #EGG_VIRTUAL_CONTROL_MASK,
+ * this function returns "&lt;Control&gt;q".
+ *
+ * The caller of this function must free the returned string.
+ */
+gchar*
+egg_virtual_accelerator_name (guint accelerator_key,
+ guint keycode,
+ EggVirtualModifierType accelerator_mods)
+{
+ static const gchar text_release[] = "<Release>";
+ static const gchar text_shift[] = "<Shift>";
+ static const gchar text_control[] = "<Control>";
+ static const gchar text_mod1[] = "<Alt>";
+ static const gchar text_mod2[] = "<Mod2>";
+ static const gchar text_mod3[] = "<Mod3>";
+ static const gchar text_mod4[] = "<Mod4>";
+ static const gchar text_mod5[] = "<Mod5>";
+ static const gchar text_meta[] = "<Meta>";
+ static const gchar text_super[] = "<Super>";
+ static const gchar text_hyper[] = "<Hyper>";
+ guint l;
+ gchar *keyval_name;
+ gchar *accelerator;
+
+ accelerator_mods &= EGG_VIRTUAL_MODIFIER_MASK;
+
+ if (!accelerator_key)
+ {
+ keyval_name = g_strdup_printf ("0x%02x", keycode);
+ }
+ else
+ {
+ keyval_name = gdk_keyval_name (gdk_keyval_to_lower (accelerator_key));
+ if (!keyval_name)
+ keyval_name = "";
+ }
+
+ l = 0;
+ if (accelerator_mods & EGG_VIRTUAL_RELEASE_MASK)
+ l += sizeof (text_release) - 1;
+ if (accelerator_mods & EGG_VIRTUAL_SHIFT_MASK)
+ l += sizeof (text_shift) - 1;
+ if (accelerator_mods & EGG_VIRTUAL_CONTROL_MASK)
+ l += sizeof (text_control) - 1;
+ if (accelerator_mods & EGG_VIRTUAL_ALT_MASK)
+ l += sizeof (text_mod1) - 1;
+ if (accelerator_mods & EGG_VIRTUAL_MOD2_MASK)
+ l += sizeof (text_mod2) - 1;
+ if (accelerator_mods & EGG_VIRTUAL_MOD3_MASK)
+ l += sizeof (text_mod3) - 1;
+ if (accelerator_mods & EGG_VIRTUAL_MOD4_MASK)
+ l += sizeof (text_mod4) - 1;
+ if (accelerator_mods & EGG_VIRTUAL_MOD5_MASK)
+ l += sizeof (text_mod5) - 1;
+ if (accelerator_mods & EGG_VIRTUAL_META_MASK)
+ l += sizeof (text_meta) - 1;
+ if (accelerator_mods & EGG_VIRTUAL_HYPER_MASK)
+ l += sizeof (text_hyper) - 1;
+ if (accelerator_mods & EGG_VIRTUAL_SUPER_MASK)
+ l += sizeof (text_super) - 1;
+ l += strlen (keyval_name);
+
+ accelerator = g_new (gchar, l + 1);
+
+ l = 0;
+ accelerator[l] = 0;
+ if (accelerator_mods & EGG_VIRTUAL_RELEASE_MASK)
+ {
+ strcpy (accelerator + l, text_release);
+ l += sizeof (text_release) - 1;
+ }
+ if (accelerator_mods & EGG_VIRTUAL_SHIFT_MASK)
+ {
+ strcpy (accelerator + l, text_shift);
+ l += sizeof (text_shift) - 1;
+ }
+ if (accelerator_mods & EGG_VIRTUAL_CONTROL_MASK)
+ {
+ strcpy (accelerator + l, text_control);
+ l += sizeof (text_control) - 1;
+ }
+ if (accelerator_mods & EGG_VIRTUAL_ALT_MASK)
+ {
+ strcpy (accelerator + l, text_mod1);
+ l += sizeof (text_mod1) - 1;
+ }
+ if (accelerator_mods & EGG_VIRTUAL_MOD2_MASK)
+ {
+ strcpy (accelerator + l, text_mod2);
+ l += sizeof (text_mod2) - 1;
+ }
+ if (accelerator_mods & EGG_VIRTUAL_MOD3_MASK)
+ {
+ strcpy (accelerator + l, text_mod3);
+ l += sizeof (text_mod3) - 1;
+ }
+ if (accelerator_mods & EGG_VIRTUAL_MOD4_MASK)
+ {
+ strcpy (accelerator + l, text_mod4);
+ l += sizeof (text_mod4) - 1;
+ }
+ if (accelerator_mods & EGG_VIRTUAL_MOD5_MASK)
+ {
+ strcpy (accelerator + l, text_mod5);
+ l += sizeof (text_mod5) - 1;
+ }
+ if (accelerator_mods & EGG_VIRTUAL_META_MASK)
+ {
+ strcpy (accelerator + l, text_meta);
+ l += sizeof (text_meta) - 1;
+ }
+ if (accelerator_mods & EGG_VIRTUAL_HYPER_MASK)
+ {
+ strcpy (accelerator + l, text_hyper);
+ l += sizeof (text_hyper) - 1;
+ }
+ if (accelerator_mods & EGG_VIRTUAL_SUPER_MASK)
+ {
+ strcpy (accelerator + l, text_super);
+ l += sizeof (text_super) - 1;
+ }
+
+ strcpy (accelerator + l, keyval_name);
+
+ return accelerator;
+}
+
+void
+egg_keymap_resolve_virtual_modifiers (GdkKeymap *keymap,
+ EggVirtualModifierType virtual_mods,
+ GdkModifierType *concrete_mods)
+{
+ GdkModifierType concrete;
+ int i;
+ const EggModmap *modmap;
+
+ g_return_if_fail (GDK_IS_KEYMAP (keymap));
+ g_return_if_fail (concrete_mods != NULL);
+
+ modmap = egg_keymap_get_modmap (keymap);
+
+ /* Not so sure about this algorithm. */
+
+ concrete = 0;
+ i = 0;
+ while (i < EGG_MODMAP_ENTRY_LAST)
+ {
+ if (modmap->mapping[i] & virtual_mods)
+ concrete |= (1 << i);
+
+ ++i;
+ }
+
+ *concrete_mods = concrete;
+}
+
+void
+egg_keymap_virtualize_modifiers (GdkKeymap *keymap,
+ GdkModifierType concrete_mods,
+ EggVirtualModifierType *virtual_mods)
+{
+ GdkModifierType virtual;
+ int i;
+ const EggModmap *modmap;
+
+ g_return_if_fail (GDK_IS_KEYMAP (keymap));
+ g_return_if_fail (virtual_mods != NULL);
+
+ modmap = egg_keymap_get_modmap (keymap);
+
+ /* Not so sure about this algorithm. */
+
+ virtual = 0;
+ i = 0;
+ while (i < EGG_MODMAP_ENTRY_LAST)
+ {
+ if ((1 << i) & concrete_mods)
+ {
+ EggVirtualModifierType cleaned;
+
+ cleaned = modmap->mapping[i] & ~(EGG_VIRTUAL_MOD2_MASK |
+ EGG_VIRTUAL_MOD3_MASK |
+ EGG_VIRTUAL_MOD4_MASK |
+ EGG_VIRTUAL_MOD5_MASK);
+
+ if (cleaned != 0)
+ {
+ virtual |= cleaned;
+ }
+ else
+ {
+ /* Rather than dropping mod2->mod5 if not bound,
+ * go ahead and use the concrete names
+ */
+ virtual |= modmap->mapping[i];
+ }
+ }
+
+ ++i;
+ }
+
+ *virtual_mods = virtual;
+}
+
+static void
+reload_modmap (GdkKeymap *keymap,
+ EggModmap *modmap)
+{
+ XModifierKeymap *xmodmap;
+ int map_size;
+ int i;
+
+ /* FIXME multihead */
+ xmodmap = XGetModifierMapping (gdk_x11_get_default_xdisplay ());
+
+ memset (modmap->mapping, 0, sizeof (modmap->mapping));
+
+ /* there are 8 modifiers, and the first 3 are shift, shift lock,
+ * and control
+ */
+ map_size = 8 * xmodmap->max_keypermod;
+ i = 3 * xmodmap->max_keypermod;
+ while (i < map_size)
+ {
+ /* get the key code at this point in the map,
+ * see if its keysym is one we're interested in
+ */
+ int keycode = xmodmap->modifiermap[i];
+ GdkKeymapKey *keys;
+ guint *keyvals;
+ int n_entries;
+ int j;
+ EggVirtualModifierType mask;
+
+ keys = NULL;
+ keyvals = NULL;
+ n_entries = 0;
+
+ gdk_keymap_get_entries_for_keycode (keymap,
+ keycode,
+ &keys, &keyvals, &n_entries);
+
+ mask = 0;
+ j = 0;
+ while (j < n_entries)
+ {
+ if (keyvals[j] == GDK_Num_Lock)
+ mask |= EGG_VIRTUAL_NUM_LOCK_MASK;
+ else if (keyvals[j] == GDK_Scroll_Lock)
+ mask |= EGG_VIRTUAL_SCROLL_LOCK_MASK;
+ else if (keyvals[j] == GDK_Meta_L ||
+ keyvals[j] == GDK_Meta_R)
+ mask |= EGG_VIRTUAL_META_MASK;
+ else if (keyvals[j] == GDK_Hyper_L ||
+ keyvals[j] == GDK_Hyper_R)
+ mask |= EGG_VIRTUAL_HYPER_MASK;
+ else if (keyvals[j] == GDK_Super_L ||
+ keyvals[j] == GDK_Super_R)
+ mask |= EGG_VIRTUAL_SUPER_MASK;
+ else if (keyvals[j] == GDK_Mode_switch)
+ mask |= EGG_VIRTUAL_MODE_SWITCH_MASK;
+
+ ++j;
+ }
+
+ /* Mod1Mask is 1 << 3 for example, i.e. the
+ * fourth modifier, i / keyspermod is the modifier
+ * index
+ */
+ modmap->mapping[i/xmodmap->max_keypermod] |= mask;
+
+ g_free (keyvals);
+ g_free (keys);
+
+ ++i;
+ }
+
+ /* Add in the not-really-virtual fixed entries */
+ modmap->mapping[EGG_MODMAP_ENTRY_SHIFT] |= EGG_VIRTUAL_SHIFT_MASK;
+ modmap->mapping[EGG_MODMAP_ENTRY_CONTROL] |= EGG_VIRTUAL_CONTROL_MASK;
+ modmap->mapping[EGG_MODMAP_ENTRY_LOCK] |= EGG_VIRTUAL_LOCK_MASK;
+ modmap->mapping[EGG_MODMAP_ENTRY_MOD1] |= EGG_VIRTUAL_ALT_MASK;
+ modmap->mapping[EGG_MODMAP_ENTRY_MOD2] |= EGG_VIRTUAL_MOD2_MASK;
+ modmap->mapping[EGG_MODMAP_ENTRY_MOD3] |= EGG_VIRTUAL_MOD3_MASK;
+ modmap->mapping[EGG_MODMAP_ENTRY_MOD4] |= EGG_VIRTUAL_MOD4_MASK;
+ modmap->mapping[EGG_MODMAP_ENTRY_MOD5] |= EGG_VIRTUAL_MOD5_MASK;
+
+ XFreeModifiermap (xmodmap);
+}
+
+const EggModmap*
+egg_keymap_get_modmap (GdkKeymap *keymap)
+{
+ EggModmap *modmap;
+
+ /* This is all a hack, much simpler when we can just
+ * modify GDK directly.
+ */
+
+ modmap = g_object_get_data (G_OBJECT (keymap),
+ "egg-modmap");
+
+ if (modmap == NULL)
+ {
+ modmap = g_new0 (EggModmap, 1);
+
+ /* FIXME modify keymap change events with an event filter
+ * and force a reload if we get one
+ */
+
+ reload_modmap (keymap, modmap);
+
+ g_object_set_data_full (G_OBJECT (keymap),
+ "egg-modmap",
+ modmap,
+ g_free);
+ }
+
+ g_assert (modmap != NULL);
+
+ return modmap;
+}
diff --git a/lib/src/eggaccelerators.h b/lib/src/eggaccelerators.h
new file mode 100644
index 0000000..d2276d2
--- /dev/null
+++ b/lib/src/eggaccelerators.h
@@ -0,0 +1,89 @@
+/* eggaccelerators.h
+ * Copyright (C) 2002 Red Hat, Inc.
+ * Developed by Havoc Pennington
+ *
+ * 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.
+ */
+
+#ifndef __EGG_ACCELERATORS_H__
+#define __EGG_ACCELERATORS_H__
+
+#include <gtk/gtkaccelgroup.h>
+#include <gdk/gdk.h>
+
+G_BEGIN_DECLS
+
+/* Where a value is also in GdkModifierType we coincide,
+ * otherwise we don't overlap.
+ */
+typedef enum
+{
+ EGG_VIRTUAL_SHIFT_MASK = 1 << 0,
+ EGG_VIRTUAL_LOCK_MASK = 1 << 1,
+ EGG_VIRTUAL_CONTROL_MASK = 1 << 2,
+
+ EGG_VIRTUAL_ALT_MASK = 1 << 3, /* fixed as Mod1 */
+
+ EGG_VIRTUAL_MOD2_MASK = 1 << 4,
+ EGG_VIRTUAL_MOD3_MASK = 1 << 5,
+ EGG_VIRTUAL_MOD4_MASK = 1 << 6,
+ EGG_VIRTUAL_MOD5_MASK = 1 << 7,
+
+#if 0
+ 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,
+ /* 13, 14 are used by Xkb for the keyboard group */
+#endif
+
+ EGG_VIRTUAL_META_MASK = 1 << 24,
+ EGG_VIRTUAL_SUPER_MASK = 1 << 25,
+ EGG_VIRTUAL_HYPER_MASK = 1 << 26,
+ EGG_VIRTUAL_MODE_SWITCH_MASK = 1 << 27,
+ EGG_VIRTUAL_NUM_LOCK_MASK = 1 << 28,
+ EGG_VIRTUAL_SCROLL_LOCK_MASK = 1 << 29,
+
+ /* Also in GdkModifierType */
+ EGG_VIRTUAL_RELEASE_MASK = 1 << 30,
+
+ /* 28-31 24-27 20-23 16-19 12-15 8-11 4-7 0-3
+ * 7 f 0 0 0 0 f f
+ */
+ EGG_VIRTUAL_MODIFIER_MASK = 0x7f0000ff
+
+} EggVirtualModifierType;
+
+gboolean egg_accelerator_parse_virtual (const gchar *accelerator,
+ guint *accelerator_key,
+ guint *keycode,
+ EggVirtualModifierType *accelerator_mods);
+void egg_keymap_resolve_virtual_modifiers (GdkKeymap *keymap,
+ EggVirtualModifierType virtual_mods,
+ GdkModifierType *concrete_mods);
+void egg_keymap_virtualize_modifiers (GdkKeymap *keymap,
+ GdkModifierType concrete_mods,
+ EggVirtualModifierType *virtual_mods);
+
+gchar* egg_virtual_accelerator_name (guint accelerator_key,
+ guint keycode,
+ EggVirtualModifierType accelerator_mods);
+
+G_END_DECLS
+
+
+#endif /* __EGG_ACCELERATORS_H__ */
diff --git a/lib/src/gecko-browser.cpp b/lib/src/gecko-browser.cpp
new file mode 100644
index 0000000..cab07f8
--- /dev/null
+++ b/lib/src/gecko-browser.cpp
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2006 Red Hat, Inc
+ *
+ * Sugar is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Sugar 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "gecko-browser.h"
+
+#include <nsCOMPtr.h>
+#include <nsIPrefService.h>
+#include <nsServiceManagerUtils.h>
+
+void
+gecko_browser_startup(void)
+{
+ nsCOMPtr<nsIPrefService> prefService;
+
+ prefService = do_GetService(NS_PREFSERVICE_CONTRACTID);
+ NS_ENSURE_TRUE(prefService, );
+
+ nsCOMPtr<nsIPrefBranch> pref;
+ prefService->GetBranch("", getter_AddRefs(pref));
+ NS_ENSURE_TRUE(pref, );
+
+ pref->SetBoolPref ("dom.disable_open_during_load", TRUE);
+}
+
+G_DEFINE_TYPE(GeckoBrowser, gecko_browser, GTK_TYPE_MOZ_EMBED)
+
+//static guint signals[N_SIGNALS];
+
+GeckoBrowser *
+gecko_browser_new(void)
+{
+ return GECKO_BROWSER(g_object_new(GECKO_TYPE_BROWSER, NULL));
+}
+
+static void
+gecko_browser_class_init(GeckoBrowserClass *browser_class)
+{
+}
+
+GeckoBrowser *
+gecko_browser_create_window(GeckoBrowser *browser)
+{
+ return GECKO_BROWSER_GET_CLASS(browser)->create_window(browser);
+}
+
+static void
+gecko_browser_new_window_cb(GtkMozEmbed *embed,
+ GtkMozEmbed **newEmbed,
+ guint chromemask)
+{
+ GeckoBrowser *browser;
+
+ browser = gecko_browser_create_window(GECKO_BROWSER(embed));
+
+ *newEmbed = GTK_MOZ_EMBED(browser);
+}
+
+static void
+gecko_browser_init(GeckoBrowser *browser)
+{
+ g_signal_connect(G_OBJECT(browser), "new-window",
+ G_CALLBACK(gecko_browser_new_window_cb), NULL);
+}
diff --git a/lib/src/gecko-browser.h b/lib/src/gecko-browser.h
new file mode 100644
index 0000000..d41d2c5
--- /dev/null
+++ b/lib/src/gecko-browser.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2006 Red Hat, Inc
+ *
+ * Sugar is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Sugar 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GECKO_BROWSER_H__
+#define __GECKO_BROWSER_H__
+
+#include <gtkmozembed.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GeckoBrowser GeckoBrowser;
+typedef struct _GeckoBrowserClass GeckoBrowserClass;
+typedef struct _GeckoBrowserPrivate GeckoBrowserPrivate;
+
+#define GECKO_TYPE_BROWSER (gecko_browser_get_type())
+#define GECKO_BROWSER(object) (G_TYPE_CHECK_INSTANCE_CAST((object), GECKO_TYPE_BROWSER, GeckoBrowser))
+#define GECKO_BROWSER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GECKO_TYPE_BROWSER, GeckoBrowserClass))
+#define GECKO_IS_BROWSER(object) (G_TYPE_CHECK_INSTANCE_TYPE((object), GECKO_TYPE_BROWSER))
+#define GECKO_IS_BROWSER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GECKO_TYPE_BROWSER))
+#define GECKO_BROWSER_GET_CLASS(object) (G_TYPE_INSTANCE_GET_CLASS((object), GECKO_TYPE_BROWSER, GeckoBrowserClass))
+
+struct _GeckoBrowser {
+ GtkMozEmbed base_instance;
+};
+
+struct _GeckoBrowserClass {
+ GtkMozEmbedClass base_class;
+
+ GeckoBrowser * (* create_window) (GeckoBrowser *browser);
+};
+
+GType gecko_browser_get_type (void);
+void gecko_browser_startup (void);
+GeckoBrowser *gecko_browser_new (void);
+GeckoBrowser *gecko_browser_create_window (GeckoBrowser *browser);
+
+G_END_DECLS
+
+#endif
diff --git a/lib/src/sugar-key-grabber.c b/lib/src/sugar-key-grabber.c
new file mode 100644
index 0000000..f31e012
--- /dev/null
+++ b/lib/src/sugar-key-grabber.c
@@ -0,0 +1,249 @@
+/*
+ * Copyright (C) 2006 Red Hat, Inc
+ *
+ * Sugar is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Sugar 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <X11/X.h>
+#include <gdk/gdkscreen.h>
+#include <gdk/gdkx.h>
+#include <gdk/gdk.h>
+
+#include "sugar-key-grabber.h"
+#include "eggaccelerators.h"
+
+/* we exclude shift, GDK_CONTROL_MASK and GDK_MOD1_MASK since we know what
+ these modifiers mean
+ these are the mods whose combinations are bound by the keygrabbing code */
+#define IGNORED_MODS (0x2000 /*Xkb modifier*/ | GDK_LOCK_MASK | \
+ GDK_MOD2_MASK | GDK_MOD3_MASK | GDK_MOD4_MASK | GDK_MOD5_MASK)
+/* these are the ones we actually use for global keys, we always only check
+ * for these set */
+#define USED_MODS (GDK_SHIFT_MASK | GDK_CONTROL_MASK | GDK_MOD1_MASK)
+
+struct _SugarKeyGrabber {
+ GObject base_instance;
+
+ GdkWindow *root;
+ GList *keys;
+};
+
+struct _SugarKeyGrabberClass {
+ GObjectClass base_class;
+
+ void (* key_pressed) (SugarKeyGrabber *grabber,
+ const char *key);
+ void (* key_released) (SugarKeyGrabber *grabber,
+ const char *key);
+};
+
+enum {
+ KEY_PRESSED,
+ KEY_RELEASED,
+ N_SIGNALS
+};
+
+typedef struct {
+ char *key;
+ guint keysym;
+ guint state;
+ guint keycode;
+} Key;
+
+G_DEFINE_TYPE(SugarKeyGrabber, sugar_key_grabber, G_TYPE_OBJECT)
+
+static guint signals[N_SIGNALS];
+
+static void
+free_key_info(Key *key_info)
+{
+ g_free(key_info->key);
+ g_free(key_info);
+}
+
+static void
+sugar_key_grabber_dispose (GObject *object)
+{
+ SugarKeyGrabber *grabber = SUGAR_KEY_GRABBER(object);
+
+ if (grabber->keys) {
+ g_list_foreach(grabber->keys, (GFunc)free_key_info, NULL);
+ g_list_free(grabber->keys);
+ grabber->keys = NULL;
+ }
+}
+
+static void
+sugar_key_grabber_class_init(SugarKeyGrabberClass *grabber_class)
+{
+ GObjectClass *g_object_class = G_OBJECT_CLASS (grabber_class);
+
+ g_object_class->dispose = sugar_key_grabber_dispose;
+
+ signals[KEY_PRESSED] = g_signal_new ("key-pressed",
+ G_TYPE_FROM_CLASS (grabber_class),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+ G_STRUCT_OFFSET (SugarKeyGrabberClass, key_pressed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__STRING,
+ G_TYPE_NONE, 1,
+ G_TYPE_STRING);
+ signals[KEY_RELEASED] = g_signal_new ("key-released",
+ G_TYPE_FROM_CLASS (grabber_class),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+ G_STRUCT_OFFSET (SugarKeyGrabberClass, key_released),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__STRING,
+ G_TYPE_NONE, 1,
+ G_TYPE_STRING);
+}
+
+static char *
+get_key_from_event(SugarKeyGrabber *grabber, XEvent *xev)
+{
+ GList *l;
+ guint keycode, state;
+
+ keycode = xev->xkey.keycode;
+ state = xev->xkey.state;
+
+ for (l = grabber->keys; l != NULL; l = l->next) {
+ Key *keyinfo = (Key *)l->data;
+ if (keyinfo->keycode == keycode &&
+ (state & USED_MODS) == keyinfo->state) {
+ return g_strdup(keyinfo->key);
+ }
+ }
+
+ return NULL;
+}
+
+static GdkFilterReturn
+filter_events(GdkXEvent *xevent, GdkEvent *event, gpointer data)
+{
+ SugarKeyGrabber *grabber = (SugarKeyGrabber *)data;
+ XEvent *xev = (XEvent *)xevent;
+
+ if (xev->type == KeyRelease) {
+ char *key;
+
+ key = get_key_from_event(grabber, xevent);
+ if (key) {
+ g_signal_emit (grabber, signals[KEY_RELEASED], 0, key);
+ g_free(key);
+
+ XUngrabKeyboard (GDK_WINDOW_XDISPLAY (grabber->root), 0L);
+
+ return GDK_FILTER_REMOVE;
+ }
+ }
+
+ if (xev->type == KeyPress) {
+ char *key;
+
+ key = get_key_from_event(grabber, xevent);
+ if (key) {
+ g_signal_emit (grabber, signals[KEY_PRESSED], 0, key);
+ g_free(key);
+
+ XGrabKeyboard (GDK_WINDOW_XDISPLAY (grabber->root),
+ GDK_WINDOW_XID (grabber->root),
+ 0, GrabModeAsync, GrabModeAsync, 0L);
+
+ return GDK_FILTER_REMOVE;
+ }
+ }
+
+ return GDK_FILTER_CONTINUE;
+}
+
+static void
+sugar_key_grabber_init(SugarKeyGrabber *grabber)
+{
+ GdkScreen *screen;
+
+ screen = gdk_screen_get_default();
+ grabber->root = gdk_screen_get_root_window(screen);
+ grabber->keys = NULL;
+
+ gdk_window_add_filter(grabber->root, filter_events, grabber);
+}
+
+/* grab_key and grab_key_real are from
+ * gnome-control-center/gnome-settings-daemon/gnome-settings-multimedia-keys.c
+ */
+
+static gboolean
+grab_key_real (Key *key, GdkWindow *root, gboolean grab, int result)
+{
+ gdk_error_trap_push ();
+ if (grab)
+ XGrabKey (GDK_DISPLAY(), key->keycode, (result | key->state),
+ GDK_WINDOW_XID (root), True, GrabModeAsync, GrabModeAsync);
+ else
+ XUngrabKey(GDK_DISPLAY(), key->keycode, (result | key->state),
+ GDK_WINDOW_XID (root));
+ gdk_flush ();
+
+ gdk_error_trap_pop ();
+
+ return TRUE;
+}
+
+#define N_BITS 32
+static void
+grab_key (SugarKeyGrabber *grabber, Key *key, gboolean grab)
+{
+ int indexes[N_BITS];/*indexes of bits we need to flip*/
+ int i, bit, bits_set_cnt;
+ int uppervalue;
+ guint mask_to_traverse = IGNORED_MODS & ~ key->state;
+
+ bit = 0;
+ for (i = 0; i < N_BITS; i++) {
+ if (mask_to_traverse & (1<<i))
+ indexes[bit++]=i;
+ }
+
+ bits_set_cnt = bit;
+
+ uppervalue = 1<<bits_set_cnt;
+ for (i = 0; i < uppervalue; i++) {
+ int j, result = 0;
+
+ for (j = 0; j < bits_set_cnt; j++) {
+ if (i & (1<<j))
+ result |= (1<<indexes[j]);
+ }
+
+ if (grab_key_real (key, grabber->root, grab, result) == FALSE)
+ return;
+ }
+}
+
+void
+sugar_key_grabber_grab(SugarKeyGrabber *grabber, const char *key)
+{
+ Key *keyinfo;
+
+ keyinfo = g_new0 (Key, 1);
+ keyinfo->key = g_strdup(key);
+ egg_accelerator_parse_virtual (key, &keyinfo->keysym,
+ &keyinfo->keycode, &keyinfo->state);
+
+ grab_key(grabber, keyinfo, TRUE);
+
+ grabber->keys = g_list_append(grabber->keys, keyinfo);
+}
diff --git a/lib/src/sugar-key-grabber.h b/lib/src/sugar-key-grabber.h
new file mode 100644
index 0000000..3791e02
--- /dev/null
+++ b/lib/src/sugar-key-grabber.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2006 Red Hat, Inc
+ *
+ * Sugar is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Sugar 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __SUGAR_KEY_GRABBER_H__
+#define __SUGAR_KEY_GRABBER_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+typedef struct _SugarKeyGrabber SugarKeyGrabber;
+typedef struct _SugarKeyGrabberClass SugarKeyGrabberClass;
+typedef struct _SugarKeyGrabberPrivate SugarKeyGrabberPrivate;
+
+#define SUGAR_TYPE_KEY_GRABBER (sugar_key_grabber_get_type())
+#define SUGAR_KEY_GRABBER(object) (G_TYPE_CHECK_INSTANCE_CAST((object), SUGAR_TYPE_KEY_GRABBER, SugarKeyGrabber))
+#define SUGAR_KEY_GRABBER_CLASS(klass) (G_TYPE_CHACK_CLASS_CAST((klass), SUGAR_TYPE_KEY_GRABBER, SugarKeyGrabberClass))
+#define SUGAR_IS_KEY_GRABBER(object) (G_TYPE_CHECK_INSTANCE_TYPE((object), SUGAR_TYPE_KEY_GRABBER))
+#define SUGAR_IS_KEYGRABBER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), SUGAR_TYPE_KEY_GRABBER))
+#define SUGAR_KEY_GRABBER_GET_CLASS(object) (G_TYPE_INSTANCE_GET_CLASS((object), SUGAR_TYPE_KEY_GRABBER, SugarKeyGrabberClass))
+
+GType sugar_key_grabber_get_type (void);
+GObject *sugar_key_grabber_new (void);
+void sugar_key_grabber_grab (SugarKeyGrabber *grabber,
+ const char *key);
+
+G_END_DECLS
+
+#endif /* __SUGAR_KEY_GRABBER_H__ */
diff --git a/lib/threadframe/GNUmakefile.mingw2 b/lib/threadframe/GNUmakefile.mingw2
new file mode 100644
index 0000000..f5c0df4
--- /dev/null
+++ b/lib/threadframe/GNUmakefile.mingw2
@@ -0,0 +1,18 @@
+PYTHON:= $(shell python -c "import sys;print '%%d%%d' %% sys.version_info[:2]")
+
+threadframe.pyd: threadframe.o libpython$(PYTHON).a
+ dllwrap --dllname threadframe.pyd --driver-name=gcc --def threadframe.def -o threadframe.pyd threadframe.o -s --entry _DllMain@12 --target=i386-mingw32 -L. -lpython$(PYTHON)
+
+threadframe.o: threadframemodule.c
+ gcc -I"C:\Program Files\Python$(PYTHON)\include" -O3 -c -o $@ -DNDEBUG $<
+libpython$(PYTHON).a: python$(PYTHON).def C:\WINNT\system32\python$(PYTHON).dll
+ dlltool --dllname python$(PYTHON).dll --def python$(PYTHON).def --output-lib libpython$(PYTHON).a
+
+python$(PYTHON).def: C:\WINNT\system32\python$(PYTHON).dll
+ pexports C:\WINNT\system32\python$(PYTHON).dll > python$(PYTHON).def
+
+clean:
+ -del threadframe.pyd
+ -del libpython$(PYTHON).a
+ -del threadframe.o
+ -del python$(PYTHON).def
diff --git a/lib/threadframe/Makefile.am b/lib/threadframe/Makefile.am
new file mode 100644
index 0000000..01ce6b1
--- /dev/null
+++ b/lib/threadframe/Makefile.am
@@ -0,0 +1,6 @@
+INCLUDES = $(PYTHON_INCLUDES)
+
+threadframedir = $(pyexecdir)
+threadframe_la_LDFLAGS = -module -avoid-version
+threadframe_LTLIBRARIES = threadframe.la
+threadframe_la_SOURCES = threadframemodule.c
diff --git a/lib/threadframe/README b/lib/threadframe/README
new file mode 100644
index 0000000..ec63fa2
--- /dev/null
+++ b/lib/threadframe/README
@@ -0,0 +1,34 @@
+Note on the License
+Dan Williams <dcbw at redhat com> 2006-08-16
+
+Since 'setup.py' specifies the "Python" license, it is assumed that the
+threadframe package is distributed under that license, even though there
+is no license header at the top of the source file.
+
+
+
+Obtaining tracebacks on other threads in Python
+===============================================
+by Fazal Majid (www.majid.info), 2004-06-10
+
+David Beazley added advanced debugging functions to the Python interpreter,
+and they have been folded into the 2.2 release. Guido van Rossum added in
+Python 2.3 the thread ID to the interpreter state structure, and this allows
+us to produce a dictionary mapping thread IDs to frames.
+
+I used these hooks to build a debugging module that is useful when you
+are looking for deadlocks in a multithreaded application. I've built
+and tested this only on Solaris 8/x86, but the code should be pretty
+portable.
+
+Of course, I disclaim any liability if this code should crash your system,
+erase your homework, eat your dog (who also ate your homework) or otherwise
+have any undesirable effect.
+
+Building and installing
+=======================
+
+Download threadframe-0.2.tar.gz. You can use the Makefile or the setup.py
+script. There is a small test program test.py that illustrates how to use this
+module to dump stack frames of all the Python interpreter threads. A sample
+run is available for your perusal.
diff --git a/lib/threadframe/sample.txt b/lib/threadframe/sample.txt
new file mode 100644
index 0000000..f5444d8
--- /dev/null
+++ b/lib/threadframe/sample.txt
@@ -0,0 +1,37 @@
+Script started on Thu 10 Jun 2004 07:23:38 PM PDT
+bayazid ~/threadframe-0.2>python test.py
+ident of main thread is: 1
+
+launching daemon thread... done
+launching self-deadlocking thread... done
+launching thread that will die before the end... done
+[4] Spam spam spam spam. Lovely spam! Wonderful spam!
+[4] Spam spam spam spam. Lovely spam! Wonderful spam!
+[4] Spam spam spam spam. Lovely spam! Wonderful spam!
+[4] Spam spam spam spam. Lovely spam! Wonderful spam!
+------------------------------------------------------------------------
+[1] 4
+ File "test.py", line 56, in ?
+ traceback.print_stack(frame)
+------------------------------------------------------------------------
+[4] 4
+ File "/usr/local/lib/python2.3/threading.py", line 436, in __bootstrap
+ self.run()
+ File "test.py", line 6, in run
+ time.sleep(1)
+------------------------------------------------------------------------
+[5] 4
+ File "/usr/local/lib/python2.3/threading.py", line 436, in __bootstrap
+ self.run()
+ File "test.py", line 13, in run
+ U_lock.acquire()
+------------------------------------------------------------------------
+[6] 3
+ File "/usr/local/lib/python2.3/threading.py", line 455, in __bootstrap
+ pass
+ File "test.py", line 20, in run
+ V_event.wait()
+ File "/usr/local/lib/python2.3/threading.py", line 352, in wait
+ self.__cond.release()
+ File "/usr/local/lib/python2.3/threading.py", line 235, in wait
+ self._acquire_restore(saved_state)
diff --git a/lib/threadframe/setup.py b/lib/threadframe/setup.py
new file mode 100644
index 0000000..df8f46d
--- /dev/null
+++ b/lib/threadframe/setup.py
@@ -0,0 +1,21 @@
+from distutils.core import setup
+from distutils.extension import Extension
+
+setup(
+ name = 'threadframe',
+ version = '0.2',
+ description = "Advanced thread debugging extension",
+ long_description = "Obtaining tracebacks on other threads than the current thread",
+ url = 'http://www.majid.info/mylos/stories/2004/06/10/threadframe.html',
+ maintainer = 'Fazal Majid',
+ maintainer_email = 'threadframe@majid.info',
+ license = 'Python',
+ platforms = [],
+ keywords = ['threading', 'thread'],
+
+ ext_modules=[
+ Extension('threadframe',
+ ['threadframemodule.c'],
+ ),
+ ],
+)
diff --git a/lib/threadframe/test.py b/lib/threadframe/test.py
new file mode 100644
index 0000000..6f1c82a
--- /dev/null
+++ b/lib/threadframe/test.py
@@ -0,0 +1,57 @@
+import sys, time, threading, thread, os, traceback, threadframe, pprint
+# daemon thread that spouts Monty Pythonesque nonsense
+class T(threading.Thread):
+ def run(self):
+ while 1:
+ time.sleep(1)
+ print '[%d] Spam spam spam spam. Lovely spam! Wonderful spam!' % ( thread.get_ident(), )
+# thread that cause a deliberate deadlock with itself
+U_lock = threading.Lock()
+class U(threading.Thread):
+ def run(self):
+ U_lock.acquire()
+ U_lock.acquire()
+# thread that will exit after the thread frames are extracted but before
+# they are printed
+V_event = threading.Event()
+class V(threading.Thread):
+ def run(self):
+ V_event.clear()
+ V_event.wait()
+
+print 'ident of main thread is: %d' % (thread.get_ident(),)
+print
+print 'launching daemon thread...',
+T().start()
+print 'done'
+print 'launching self-deadlocking thread...',
+U().start()
+print 'done'
+print 'launching thread that will die before the end...',
+v = V()
+v.start()
+print 'done'
+
+time.sleep(5)
+
+# Python 2.2 does not support threadframe.dict()
+if sys.hexversion < 0x02030000:
+ frames = threadframe.threadframe()
+else:
+ frames = threadframe.dict()
+
+# signal the thread V to die, then wait for it to oblige
+V_event.set()
+v.join()
+
+if sys.hexversion < 0x02030000:
+ for frame in frames:
+ print '-' * 72
+ print 'frame ref count = %d' % sys.getrefcount(frame)
+ traceback.print_stack(frame)
+else:
+ for thread_id, frame in frames.iteritems():
+ print '-' * 72
+ print '[%s] %d' % (thread_id, sys.getrefcount(frame))
+ traceback.print_stack(frame)
+os._exit(0)
diff --git a/lib/threadframe/threadframe.def b/lib/threadframe/threadframe.def
new file mode 100644
index 0000000..713e4b2
--- /dev/null
+++ b/lib/threadframe/threadframe.def
@@ -0,0 +1,3 @@
+EXPORTS
+ initthreadframe
+
diff --git a/lib/threadframe/threadframemodule.c b/lib/threadframe/threadframemodule.c
new file mode 100644
index 0000000..2f67a45
--- /dev/null
+++ b/lib/threadframe/threadframemodule.c
@@ -0,0 +1,111 @@
+/*
+ * module to access the stack frame of all Python interpreter threads
+ *
+ * works on Solaris and OS X, portability to other OSes unknown
+ *
+ * Fazal Majid, 2002-10-11
+ *
+ * with contributions from Bob Ippolito (http://bob.pycs.net/)
+ *
+ * Copyright (c) 2002-2004 Kefta Inc.
+ * All rights reserved
+ *
+ */
+
+#include "Python.h"
+#include "compile.h"
+#include "frameobject.h"
+#include "patchlevel.h"
+
+static PyObject *
+threadframe_threadframe(PyObject *self, PyObject *args) {
+ PyInterpreterState *interp;
+ PyThreadState *tstate;
+ PyFrameObject *frame;
+ PyListObject *frames;
+
+ frames = (PyListObject*) PyList_New(0);
+ if (! frames) return NULL;
+
+ /* Walk down the interpreters and threads until we find the one
+ matching the supplied thread ID. */
+ for (interp = PyInterpreterState_Head(); interp != NULL;
+ interp = interp->next) {
+ for(tstate = interp->tstate_head; tstate != NULL;
+ tstate = tstate->next) {
+ frame = tstate->frame;
+ if (! frame) continue;
+ Py_INCREF(frame);
+ PyList_Append((PyObject*) frames, (PyObject*) frame);
+ }
+ }
+ return (PyObject*) frames;
+}
+
+/* the PyThreadState gained a thread_id member only in 2.3rc1 */
+static PyObject *
+threadframe_dict(PyObject *self, PyObject *args) {
+#if PY_VERSION_HEX < 0x02030000
+ PyErr_SetString(PyExc_NotImplementedError,
+ "threadframe.dict() requires Python 2.3 or later");
+ return NULL;
+#else
+ PyInterpreterState *interp;
+ PyThreadState *tstate;
+ PyFrameObject *frame;
+ PyObject *frames;
+
+ frames = (PyObject*) PyDict_New();
+ if (! frames) return NULL;
+
+ /* Walk down the interpreters and threads until we find the one
+ matching the supplied thread ID. */
+ for (interp = PyInterpreterState_Head(); interp != NULL;
+ interp = interp->next) {
+ for(tstate = interp->tstate_head; tstate != NULL;
+ tstate = tstate->next) {
+ PyObject *thread_id;
+ frame = tstate->frame;
+ if (! frame) continue;
+ thread_id = PyInt_FromLong(tstate->thread_id);
+ PyDict_SetItem(frames, thread_id, (PyObject*)frame);
+ Py_DECREF(thread_id);
+ }
+ }
+ return frames;
+#endif
+}
+
+static char threadframe_doc[] =
+"Returns a list of frame objects for all threads.\n"
+"(equivalent to dict().values() on 2.3 and later).";
+
+static char threadframe_dict_doc[] =
+"Returns a dictionary, mapping for all threads the thread ID\n"
+"(as returned by thread.get_ident() or by the keys to threading._active)\n"
+"to the corresponding frame object.\n"
+"Raises NotImplementedError on Python 2.2.";
+
+/* List of functions defined in the module */
+
+static PyMethodDef threadframe_methods[] = {
+ {"threadframe", threadframe_threadframe, METH_VARARGS, threadframe_doc},
+ {"dict", threadframe_dict, METH_VARARGS, threadframe_dict_doc},
+ {NULL, NULL} /* sentinel */
+};
+
+
+/* Initialization function for the module (*must* be called initthreadframe) */
+
+static char module_doc[] =
+"Debugging module to extract stack frames for all Python interpreter heads.\n"
+"Useful in conjunction with traceback.print_stack().\n";
+
+DL_EXPORT(void)
+initthreadframe(void)
+{
+ PyObject *m;
+
+ /* Create the module and add the functions */
+ m = Py_InitModule3("threadframe", threadframe_methods, module_doc);
+}