Add support for WM_PROTOCOLS to the ClutterStage window
Supporting WM_PROTOCOLS allows handling the WM_DELETE_WINDOW ClientMessage, which is then relayed to the ClutterStage actor in form of the "delete-event" signal. Returning TRUE will block the propagation and won't close the stage window.
This commit is contained in:
parent
f1a1399927
commit
b2d01d86c2
@ -58,7 +58,8 @@ typedef enum
|
|||||||
CLUTTER_SCROLL,
|
CLUTTER_SCROLL,
|
||||||
CLUTTER_STAGE_STATE,
|
CLUTTER_STAGE_STATE,
|
||||||
CLUTTER_DESTROY_NOTIFY,
|
CLUTTER_DESTROY_NOTIFY,
|
||||||
CLUTTER_CLIENT_MESSAGE
|
CLUTTER_CLIENT_MESSAGE,
|
||||||
|
CLUTTER_DELETE
|
||||||
} ClutterEventType;
|
} ClutterEventType;
|
||||||
|
|
||||||
typedef enum
|
typedef enum
|
||||||
@ -80,6 +81,7 @@ typedef enum
|
|||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
CLUTTER_FILTER_CONTINUE,
|
CLUTTER_FILTER_CONTINUE,
|
||||||
|
CLUTTER_FILTER_TRANSLATE,
|
||||||
CLUTTER_FILTER_REMOVE
|
CLUTTER_FILTER_REMOVE
|
||||||
} ClutterFilterResponse;
|
} ClutterFilterResponse;
|
||||||
|
|
||||||
|
@ -153,11 +153,23 @@ clutter_main_do_event (ClutterEvent *event,
|
|||||||
case CLUTTER_MOTION:
|
case CLUTTER_MOTION:
|
||||||
g_signal_emit_by_name (stage, "motion-event", event);
|
g_signal_emit_by_name (stage, "motion-event", event);
|
||||||
break;
|
break;
|
||||||
case CLUTTER_DESTROY_NOTIFY:
|
case CLUTTER_DELETE:
|
||||||
g_signal_emit_by_name (stage, "delete-event");
|
{
|
||||||
|
gboolean res = FALSE;
|
||||||
|
|
||||||
|
g_object_ref (stage);
|
||||||
|
g_signal_emit_by_name (stage, "delete-event", event, &res);
|
||||||
|
if (!res)
|
||||||
|
clutter_main_quit ();
|
||||||
|
g_object_unref (stage);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case CLUTTER_STAGE_STATE:
|
case CLUTTER_STAGE_STATE:
|
||||||
break;
|
break;
|
||||||
|
case CLUTTER_DESTROY_NOTIFY:
|
||||||
|
break;
|
||||||
|
case CLUTTER_CLIENT_MESSAGE:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,19 +92,6 @@ enum
|
|||||||
|
|
||||||
static guint stage_signals[LAST_SIGNAL] = { 0 };
|
static guint stage_signals[LAST_SIGNAL] = { 0 };
|
||||||
|
|
||||||
static gboolean
|
|
||||||
clutter_stage_delete_event (ClutterStage *stage,
|
|
||||||
ClutterAnyEvent *event)
|
|
||||||
{
|
|
||||||
/* FIXME - destroy the main stage, probably attaching a weak ref
|
|
||||||
* to it from the backend, so that it gets destroyed too.
|
|
||||||
*/
|
|
||||||
CLUTTER_NOTE (EVENT, "Received a destroy notification");
|
|
||||||
|
|
||||||
/* we don't want to block */
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
clutter_stage_paint (ClutterActor *actor)
|
clutter_stage_paint (ClutterActor *actor)
|
||||||
{
|
{
|
||||||
@ -208,8 +195,6 @@ clutter_stage_class_init (ClutterStageClass *klass)
|
|||||||
|
|
||||||
actor_class->paint = clutter_stage_paint;
|
actor_class->paint = clutter_stage_paint;
|
||||||
|
|
||||||
stage_class->delete_event = clutter_stage_delete_event;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ClutterStage:fullscreen
|
* ClutterStage:fullscreen
|
||||||
*
|
*
|
||||||
|
@ -61,6 +61,8 @@
|
|||||||
#define XEMBED_ACTIVATE_ACCELERATOR 14
|
#define XEMBED_ACTIVATE_ACCELERATOR 14
|
||||||
|
|
||||||
static Atom Atom_XEMBED = 0;
|
static Atom Atom_XEMBED = 0;
|
||||||
|
static Atom Atom_WM_PROTOCOLS = 0;
|
||||||
|
|
||||||
static Window ParentEmbedderWin = None;
|
static Window ParentEmbedderWin = None;
|
||||||
|
|
||||||
typedef struct _ClutterEventSource ClutterEventSource;
|
typedef struct _ClutterEventSource ClutterEventSource;
|
||||||
@ -172,6 +174,7 @@ _clutter_events_init (ClutterBackend *backend)
|
|||||||
CLUTTER_NOTE (EVENT, "Connection number: %d", connection_number);
|
CLUTTER_NOTE (EVENT, "Connection number: %d", connection_number);
|
||||||
|
|
||||||
Atom_XEMBED = XInternAtom (backend_glx->xdpy, "_XEMBED", False);
|
Atom_XEMBED = XInternAtom (backend_glx->xdpy, "_XEMBED", False);
|
||||||
|
Atom_WM_PROTOCOLS = XInternAtom (backend_glx->xdpy, "WM_PROTOCOLS", False);
|
||||||
|
|
||||||
source = backend_glx->event_source = clutter_event_source_new (backend);
|
source = backend_glx->event_source = clutter_event_source_new (backend);
|
||||||
event_source = (ClutterEventSource *) source;
|
event_source = (ClutterEventSource *) source;
|
||||||
@ -213,12 +216,11 @@ _clutter_events_uninit (ClutterBackend *backend)
|
|||||||
static void
|
static void
|
||||||
set_user_time (Display *display,
|
set_user_time (Display *display,
|
||||||
Window *xwindow,
|
Window *xwindow,
|
||||||
ClutterEvent *event)
|
long timestamp)
|
||||||
{
|
{
|
||||||
if (clutter_event_get_time (event) != CLUTTER_CURRENT_TIME)
|
if (timestamp != CLUTTER_CURRENT_TIME)
|
||||||
{
|
{
|
||||||
Atom atom_WM_USER_TIME;
|
Atom atom_WM_USER_TIME;
|
||||||
long timestamp = clutter_event_get_time (event);
|
|
||||||
|
|
||||||
atom_WM_USER_TIME = XInternAtom (display, "_NET_WM_USER_TIME", False);
|
atom_WM_USER_TIME = XInternAtom (display, "_NET_WM_USER_TIME", False);
|
||||||
|
|
||||||
@ -282,7 +284,43 @@ translate_key_event (ClutterBackend *backend,
|
|||||||
0); /* FIXME: index with modifiers */
|
0); /* FIXME: index with modifiers */
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static gboolean
|
||||||
|
handle_wm_protocols_event (ClutterBackendGlx *backend_glx,
|
||||||
|
XEvent *xevent)
|
||||||
|
{
|
||||||
|
Atom atom = (Atom) xevent->xclient.data.l[0];
|
||||||
|
Atom Atom_WM_DELETE_WINDOW;
|
||||||
|
|
||||||
|
ClutterStage *stage = CLUTTER_STAGE (backend_glx->stage);
|
||||||
|
Window stage_xwindow = clutter_glx_get_stage_window (stage);
|
||||||
|
|
||||||
|
Atom_WM_DELETE_WINDOW = XInternAtom (backend_glx->xdpy,
|
||||||
|
"WM_DELETE_WINDOW",
|
||||||
|
False);
|
||||||
|
|
||||||
|
if (atom == Atom_WM_DELETE_WINDOW &&
|
||||||
|
xevent->xany.window == stage_xwindow)
|
||||||
|
{
|
||||||
|
/* the WM_DELETE_WINDOW is a request: we do not destroy
|
||||||
|
* the window right away, as it might contain vital data;
|
||||||
|
* we relay the event to the application and we let it
|
||||||
|
* handle the request
|
||||||
|
*/
|
||||||
|
CLUTTER_NOTE (EVENT, "delete window:\twindow: %ld",
|
||||||
|
xevent->xclient.window);
|
||||||
|
|
||||||
|
set_user_time (backend_glx->xdpy,
|
||||||
|
&stage_xwindow,
|
||||||
|
xevent->xclient.data.l[1]);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* do not send the WM_PROTOCOLS events to the queue */
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
handle_xembed_event (ClutterBackendGlx *backend_glx,
|
handle_xembed_event (ClutterBackendGlx *backend_glx,
|
||||||
XEvent *xevent)
|
XEvent *xevent)
|
||||||
{
|
{
|
||||||
@ -322,6 +360,9 @@ handle_xembed_event (ClutterBackendGlx *backend_glx,
|
|||||||
CLUTTER_NOTE (EVENT, "got unknown XEMBED message");
|
CLUTTER_NOTE (EVENT, "got unknown XEMBED message");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* do not propagate the XEMBED events to the stage */
|
||||||
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
@ -366,7 +407,7 @@ clutter_event_translate (ClutterBackend *backend,
|
|||||||
case KeyPress:
|
case KeyPress:
|
||||||
event->type = CLUTTER_KEY_PRESS;
|
event->type = CLUTTER_KEY_PRESS;
|
||||||
translate_key_event (backend, event, xevent);
|
translate_key_event (backend, event, xevent);
|
||||||
set_user_time (backend_glx->xdpy, &xwindow, event);
|
set_user_time (backend_glx->xdpy, &xwindow, xevent->xkey.time);
|
||||||
break;
|
break;
|
||||||
case KeyRelease:
|
case KeyRelease:
|
||||||
event->type = CLUTTER_KEY_RELEASE;
|
event->type = CLUTTER_KEY_RELEASE;
|
||||||
@ -408,7 +449,7 @@ clutter_event_translate (ClutterBackend *backend,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
set_user_time (backend_glx->xdpy, &xwindow, event);
|
set_user_time (backend_glx->xdpy, &xwindow, event->button.time);
|
||||||
break;
|
break;
|
||||||
case ButtonRelease:
|
case ButtonRelease:
|
||||||
/* scroll events don't have a corresponding release */
|
/* scroll events don't have a corresponding release */
|
||||||
@ -442,9 +483,16 @@ clutter_event_translate (ClutterBackend *backend,
|
|||||||
break;
|
break;
|
||||||
case ClientMessage:
|
case ClientMessage:
|
||||||
CLUTTER_NOTE (EVENT, "client message");
|
CLUTTER_NOTE (EVENT, "client message");
|
||||||
if (xevent->xclient.message_type == Atom_XEMBED)
|
|
||||||
handle_xembed_event (backend_glx, xevent);
|
|
||||||
event->type = event->any.type = CLUTTER_CLIENT_MESSAGE;
|
event->type = event->any.type = CLUTTER_CLIENT_MESSAGE;
|
||||||
|
|
||||||
|
if (xevent->xclient.message_type == Atom_XEMBED)
|
||||||
|
res = handle_xembed_event (backend_glx, xevent);
|
||||||
|
else if (xevent->xclient.message_type == Atom_WM_PROTOCOLS)
|
||||||
|
{
|
||||||
|
res = handle_wm_protocols_event (backend_glx, xevent);
|
||||||
|
event->type = event->any.type = CLUTTER_DELETE;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
/* ignore every other event */
|
/* ignore every other event */
|
||||||
|
@ -108,6 +108,20 @@ clutter_stage_glx_unrealize (ClutterActor *actor)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
set_wm_protocols (Display *xdisplay,
|
||||||
|
Window xwindow)
|
||||||
|
{
|
||||||
|
Atom protocols[3];
|
||||||
|
int n = 0;
|
||||||
|
|
||||||
|
protocols[n++] = XInternAtom (xdisplay, "WM_DELETE_WINDOW", False);
|
||||||
|
protocols[n++] = XInternAtom (xdisplay, "WM_TAKE_FOCUS", False);
|
||||||
|
protocols[n++] = XInternAtom (xdisplay, "_NET_WM_PING", False);
|
||||||
|
|
||||||
|
XSetWMProtocols (xdisplay, xwindow, protocols, n);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
clutter_stage_glx_realize (ClutterActor *actor)
|
clutter_stage_glx_realize (ClutterActor *actor)
|
||||||
{
|
{
|
||||||
@ -168,6 +182,8 @@ clutter_stage_glx_realize (ClutterActor *actor)
|
|||||||
ButtonPressMask | ButtonReleaseMask |
|
ButtonPressMask | ButtonReleaseMask |
|
||||||
PropertyChangeMask);
|
PropertyChangeMask);
|
||||||
|
|
||||||
|
set_wm_protocols (stage_glx->xdpy, stage_glx->xwin);
|
||||||
|
|
||||||
if (stage_glx->gl_context)
|
if (stage_glx->gl_context)
|
||||||
glXDestroyContext (stage_glx->xdpy, stage_glx->gl_context);
|
glXDestroyContext (stage_glx->xdpy, stage_glx->gl_context);
|
||||||
|
|
||||||
|
@ -47,6 +47,7 @@ Windowing events handled by Clutter.
|
|||||||
</para>
|
</para>
|
||||||
|
|
||||||
@CLUTTER_FILTER_CONTINUE:
|
@CLUTTER_FILTER_CONTINUE:
|
||||||
|
@CLUTTER_FILTER_TRANSLATE:
|
||||||
@CLUTTER_FILTER_REMOVE:
|
@CLUTTER_FILTER_REMOVE:
|
||||||
|
|
||||||
<!-- ##### ENUM ClutterScrollDirection ##### -->
|
<!-- ##### ENUM ClutterScrollDirection ##### -->
|
||||||
@ -86,6 +87,7 @@ Windowing events handled by Clutter.
|
|||||||
@CLUTTER_STAGE_STATE:
|
@CLUTTER_STAGE_STATE:
|
||||||
@CLUTTER_DESTROY_NOTIFY:
|
@CLUTTER_DESTROY_NOTIFY:
|
||||||
@CLUTTER_CLIENT_MESSAGE:
|
@CLUTTER_CLIENT_MESSAGE:
|
||||||
|
@CLUTTER_DELETE:
|
||||||
|
|
||||||
<!-- ##### UNION ClutterEvent ##### -->
|
<!-- ##### UNION ClutterEvent ##### -->
|
||||||
<para>
|
<para>
|
||||||
|
Loading…
Reference in New Issue
Block a user