device: Allow enabling/disabling non-master devices

Slave and floating devices should always be disabled, and not deliver
events to the scene. It is up to the user to enable non-master devices
and handle events coming from them.

ClutterInputDevice gets a new :enabled property, defaulting to FALSE;
when a device manager creates a new device it has to set it to TRUE if
the :device-mode property is set to CLUTTER_INPUT_MODE_MASTER.

The main event queue entry point, _clutter_event_push(), will
automatically discard events coming from disabled devices.
This commit is contained in:
Emmanuele Bassi 2011-01-19 16:23:45 +00:00
parent 137f7d42a8
commit 73cf6bd52c
7 changed files with 100 additions and 4 deletions

View File

@ -103,7 +103,8 @@ struct _ClutterInputDevice
gint min_keycode; gint min_keycode;
gint max_keycode; gint max_keycode;
guint has_cursor : 1; guint has_cursor : 1;
guint is_enabled : 1;
}; };
struct _ClutterInputDeviceClass struct _ClutterInputDeviceClass

View File

@ -832,10 +832,19 @@ _clutter_event_push (const ClutterEvent *event,
gboolean do_copy) gboolean do_copy)
{ {
ClutterMainContext *context = _clutter_context_get_default (); ClutterMainContext *context = _clutter_context_get_default ();
ClutterInputDevice *device;
/* FIXME: check queue is valid */ /* FIXME: check queue is valid */
g_assert (context != NULL); g_assert (context != NULL);
/* disabled devices don't propagate events */
device = clutter_event_get_device (event);
if (device != NULL)
{
if (!clutter_input_device_get_enabled (device))
return;
}
if (do_copy) if (do_copy)
{ {
ClutterEvent *copy; ClutterEvent *copy;

View File

@ -59,6 +59,7 @@ enum
PROP_DEVICE_MODE, PROP_DEVICE_MODE,
PROP_HAS_CURSOR, PROP_HAS_CURSOR,
PROP_ENABLED,
PROP_N_AXES, PROP_N_AXES,
@ -139,6 +140,10 @@ clutter_input_device_set_property (GObject *gobject,
self->has_cursor = g_value_get_boolean (value); self->has_cursor = g_value_get_boolean (value);
break; break;
case PROP_ENABLED:
self->is_enabled = g_value_get_boolean (value);
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break; break;
@ -190,6 +195,10 @@ clutter_input_device_get_property (GObject *gobject,
g_value_set_uint (value, 0); g_value_set_uint (value, 0);
break; break;
case PROP_ENABLED:
g_value_set_boolean (value, self->is_enabled);
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break; break;
@ -270,6 +279,13 @@ clutter_input_device_class_init (ClutterInputDeviceClass *klass)
FALSE, FALSE,
CLUTTER_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); CLUTTER_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
obj_props[PROP_ENABLED] =
g_param_spec_boolean ("enabled",
P_("Enabled"),
P_("Whether the device is enabled"),
FALSE,
CLUTTER_PARAM_READWRITE);
obj_props[PROP_N_AXES] = obj_props[PROP_N_AXES] =
g_param_spec_uint ("n-axes", g_param_spec_uint ("n-axes",
P_("Number of Axes"), P_("Number of Axes"),
@ -587,6 +603,56 @@ clutter_input_device_get_device_id (ClutterInputDevice *device)
return device->id; return device->id;
} }
/**
* clutter_input_device_set_enabled:
* @device: a #ClutterInputDevice
* @enabled: %TRUE to enable the @device
*
* Enables or disables a #ClutterInputDevice.
*
* Only devices with a #ClutterInputDevice:device-mode property set
* to %CLUTTER_INPUT_MODE_SLAVE or %CLUTTER_INPUT_MODE_FLOATING can
* be disabled.
*
* Since: 1.6
*/
void
clutter_input_device_set_enabled (ClutterInputDevice *device,
gboolean enabled)
{
g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device));
enabled = !!enabled;
if (!enabled && device->device_mode == CLUTTER_INPUT_MODE_MASTER)
return;
if (device->is_enabled == enabled)
return;
device->is_enabled = enabled;
g_object_notify_by_pspec (G_OBJECT (device), obj_props[PROP_ENABLED]);
}
/**
* clutter_input_device_get_enabled:
* @device: a #ClutterInputDevice
*
* Retrieves whether @device is enabled.
*
* Return value: %TRUE if the device is enabled
*
* Since: 1.6
*/
gboolean
clutter_input_device_get_enabled (ClutterInputDevice *device)
{
g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), FALSE);
return device->is_enabled;
}
/** /**
* clutter_input_device_get_device_coords: * clutter_input_device_get_device_coords:
* @device: a #ClutterInputDevice of type %CLUTTER_POINTER_DEVICE * @device: a #ClutterInputDevice of type %CLUTTER_POINTER_DEVICE

View File

@ -138,6 +138,9 @@ ClutterStage * clutter_input_device_get_pointer_stage (ClutterInputDev
G_CONST_RETURN gchar * clutter_input_device_get_device_name (ClutterInputDevice *device); G_CONST_RETURN gchar * clutter_input_device_get_device_name (ClutterInputDevice *device);
ClutterInputMode clutter_input_device_get_device_mode (ClutterInputDevice *device); ClutterInputMode clutter_input_device_get_device_mode (ClutterInputDevice *device);
gboolean clutter_input_device_get_has_cursor (ClutterInputDevice *device); gboolean clutter_input_device_get_has_cursor (ClutterInputDevice *device);
void clutter_input_device_set_enabled (ClutterInputDevice *device,
gboolean enabled);
gboolean clutter_input_device_get_enabled (ClutterInputDevice *device);
guint clutter_input_device_get_n_axes (ClutterInputDevice *device); guint clutter_input_device_get_n_axes (ClutterInputDevice *device);
ClutterInputAxis clutter_input_device_get_axis (ClutterInputDevice *device, ClutterInputAxis clutter_input_device_get_axis (ClutterInputDevice *device,

View File

@ -188,6 +188,7 @@ create_device (ClutterDeviceManagerX11 *manager_x11,
"device-type", source, "device-type", source,
"device-mode", CLUTTER_INPUT_MODE_FLOATING, "device-mode", CLUTTER_INPUT_MODE_FLOATING,
"backend", backend_x11, "backend", backend_x11,
"enabled", FALSE,
NULL); NULL);
translate_class_info (retval, info); translate_class_info (retval, info);
@ -581,6 +582,7 @@ default_device:
"device-manager", manager_x11, "device-manager", manager_x11,
"device-mode", CLUTTER_INPUT_MODE_MASTER, "device-mode", CLUTTER_INPUT_MODE_MASTER,
"backend", backend_x11, "backend", backend_x11,
"enabled", TRUE,
NULL); NULL);
CLUTTER_NOTE (BACKEND, "Added core pointer device"); CLUTTER_NOTE (BACKEND, "Added core pointer device");
@ -592,6 +594,7 @@ default_device:
"device-manager", manager_x11, "device-manager", manager_x11,
"device-mode", CLUTTER_INPUT_MODE_MASTER, "device-mode", CLUTTER_INPUT_MODE_MASTER,
"backend", backend_x11, "backend", backend_x11,
"enabled", TRUE,
NULL); NULL);
CLUTTER_NOTE (BACKEND, "Added core keyboard device"); CLUTTER_NOTE (BACKEND, "Added core keyboard device");

View File

@ -159,6 +159,7 @@ create_device (ClutterDeviceManagerXI2 *manager_xi2,
ClutterInputDeviceType source; ClutterInputDeviceType source;
ClutterInputDevice *retval; ClutterInputDevice *retval;
ClutterInputMode mode; ClutterInputMode mode;
gboolean is_enabled;
if (info->use == XIMasterKeyboard || info->use == XISlaveKeyboard) if (info->use == XIMasterKeyboard || info->use == XISlaveKeyboard)
source = CLUTTER_KEYBOARD_DEVICE; source = CLUTTER_KEYBOARD_DEVICE;
@ -185,16 +186,19 @@ create_device (ClutterDeviceManagerXI2 *manager_xi2,
case XIMasterKeyboard: case XIMasterKeyboard:
case XIMasterPointer: case XIMasterPointer:
mode = CLUTTER_INPUT_MODE_MASTER; mode = CLUTTER_INPUT_MODE_MASTER;
is_enabled = TRUE;
break; break;
case XISlaveKeyboard: case XISlaveKeyboard:
case XISlavePointer: case XISlavePointer:
mode = CLUTTER_INPUT_MODE_SLAVE; mode = CLUTTER_INPUT_MODE_SLAVE;
is_enabled = FALSE;
break; break;
case XIFloatingSlave: case XIFloatingSlave:
default: default:
mode = CLUTTER_INPUT_MODE_FLOATING; mode = CLUTTER_INPUT_MODE_FLOATING;
is_enabled = FALSE;
break; break;
} }
@ -206,6 +210,7 @@ create_device (ClutterDeviceManagerXI2 *manager_xi2,
"device-type", source, "device-type", source,
"device-mode", mode, "device-mode", mode,
"backend", backend_x11, "backend", backend_x11,
"enabled", is_enabled,
NULL); NULL);
translate_device_classes (backend_x11->xdpy, retval, translate_device_classes (backend_x11->xdpy, retval,
@ -655,11 +660,14 @@ clutter_device_manager_xi2_translate_event (ClutterEventTranslator *translator,
event->key.unicode_value = (gunichar) '\0'; event->key.unicode_value = (gunichar) '\0';
} }
CLUTTER_NOTE (EVENT, "%s: win:0x%x, key: %12s (%d)", CLUTTER_NOTE (EVENT,
"%s: win:0x%x device:%d source:%d, key: %12s (%d)",
event->any.type == CLUTTER_KEY_PRESS event->any.type == CLUTTER_KEY_PRESS
? "key press " ? "key press "
: "key release", : "key release",
(unsigned int) stage_x11->xwin, (unsigned int) stage_x11->xwin,
xev->deviceid,
xev->sourceid,
event->key.keyval ? buffer : "(none)", event->key.keyval ? buffer : "(none)",
event->key.keyval); event->key.keyval);

View File

@ -196,15 +196,21 @@ test_devices_main (int argc, char **argv)
ClutterInputDeviceType device_type; ClutterInputDeviceType device_type;
ClutterActor *hand = NULL; ClutterActor *hand = NULL;
g_print ("got a %s device '%s' with id %d...\n", g_print ("got a %s device '%s' with id %d\n",
device_type_name (device), device_type_name (device),
clutter_input_device_get_device_name (device), clutter_input_device_get_device_name (device),
clutter_input_device_get_device_id (device)); clutter_input_device_get_device_id (device));
device_type = clutter_input_device_get_device_type (device); device_type = clutter_input_device_get_device_type (device);
if (device_type == CLUTTER_POINTER_DEVICE || if (device_type == CLUTTER_POINTER_DEVICE ||
device_type == CLUTTER_EXTENSION_DEVICE) device_type == CLUTTER_PEN_DEVICE ||
device_type == CLUTTER_POINTER_DEVICE)
{ {
g_print ("*** enabling device '%s' ***\n",
clutter_input_device_get_device_name (device));
clutter_input_device_set_enabled (device, TRUE);
hand = clutter_texture_new_from_file (TESTS_DATADIR hand = clutter_texture_new_from_file (TESTS_DATADIR
G_DIR_SEPARATOR_S G_DIR_SEPARATOR_S
"redhand.png", "redhand.png",