Create a private sugar lib and put our extensions there.
This commit is contained in:
@@ -0,0 +1 @@
|
||||
SUBDIRS = src python
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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")
|
||||
)
|
||||
)
|
||||
@@ -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
|
||||
_*
|
||||
%%
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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 "<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[] = "<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;
|
||||
}
|
||||
@@ -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__ */
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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__ */
|
||||
@@ -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
|
||||
@@ -0,0 +1,6 @@
|
||||
INCLUDES = $(PYTHON_INCLUDES)
|
||||
|
||||
threadframedir = $(pyexecdir)
|
||||
threadframe_la_LDFLAGS = -module -avoid-version
|
||||
threadframe_LTLIBRARIES = threadframe.la
|
||||
threadframe_la_SOURCES = threadframemodule.c
|
||||
@@ -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.
|
||||
@@ -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)
|
||||
@@ -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'],
|
||||
),
|
||||
],
|
||||
)
|
||||
@@ -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)
|
||||
@@ -0,0 +1,3 @@
|
||||
EXPORTS
|
||||
initthreadframe
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
Reference in New Issue
Block a user