From 62a46ff92b234d07437f9f36efea576996eb84e2 Mon Sep 17 00:00:00 2001 From: Marco Pesenti Gritti Date: Thu, 12 Oct 2006 10:47:17 +0000 Subject: Create a private sugar lib and put our extensions there. --- (limited to 'lib') 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 + + + +#line 4 "_sugar.override" +#include + +#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 + +#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 + +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 +#include +#include +#include + +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 "<Control>a" or "<Shift><Alt>F1" or + * "<Release>z" (the last one is for key release). The parser + * is fairly liberal and allows lower or upper case, and also + * abbreviations such as "<Ctl>" and "<Ctrl>". + * + * 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 "<Control>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[] = ""; + static const gchar text_shift[] = ""; + static const gchar text_control[] = ""; + static const gchar text_mod1[] = ""; + static const gchar text_mod2[] = ""; + static const gchar text_mod3[] = ""; + static const gchar text_mod4[] = ""; + static const gchar text_mod5[] = ""; + static const gchar text_meta[] = ""; + static const gchar text_super[] = ""; + static const gchar text_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 +#include + +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 +#include +#include + +void +gecko_browser_startup(void) +{ + nsCOMPtr prefService; + + prefService = do_GetService(NS_PREFSERVICE_CONTRACTID); + NS_ENSURE_TRUE(prefService, ); + + nsCOMPtr 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 + +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 +#include +#include +#include + +#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<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 + +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 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); +} -- cgit v0.9.1