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_STAGE_STATE,
|
||||
CLUTTER_DESTROY_NOTIFY,
|
||||
CLUTTER_CLIENT_MESSAGE
|
||||
CLUTTER_CLIENT_MESSAGE,
|
||||
CLUTTER_DELETE
|
||||
} ClutterEventType;
|
||||
|
||||
typedef enum
|
||||
@ -80,6 +81,7 @@ typedef enum
|
||||
typedef enum
|
||||
{
|
||||
CLUTTER_FILTER_CONTINUE,
|
||||
CLUTTER_FILTER_TRANSLATE,
|
||||
CLUTTER_FILTER_REMOVE
|
||||
} ClutterFilterResponse;
|
||||
|
||||
|
@ -153,11 +153,23 @@ clutter_main_do_event (ClutterEvent *event,
|
||||
case CLUTTER_MOTION:
|
||||
g_signal_emit_by_name (stage, "motion-event", event);
|
||||
break;
|
||||
case CLUTTER_DESTROY_NOTIFY:
|
||||
g_signal_emit_by_name (stage, "delete-event");
|
||||
case CLUTTER_DELETE:
|
||||
{
|
||||
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;
|
||||
case CLUTTER_STAGE_STATE:
|
||||
break;
|
||||
case CLUTTER_DESTROY_NOTIFY:
|
||||
break;
|
||||
case CLUTTER_CLIENT_MESSAGE:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -92,19 +92,6 @@ enum
|
||||
|
||||
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
|
||||
clutter_stage_paint (ClutterActor *actor)
|
||||
{
|
||||
@ -208,8 +195,6 @@ clutter_stage_class_init (ClutterStageClass *klass)
|
||||
|
||||
actor_class->paint = clutter_stage_paint;
|
||||
|
||||
stage_class->delete_event = clutter_stage_delete_event;
|
||||
|
||||
/**
|
||||
* ClutterStage:fullscreen
|
||||
*
|
||||
|
@ -60,7 +60,9 @@
|
||||
#define XEMBED_UNREGISTER_ACCELERATOR 13
|
||||
#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;
|
||||
|
||||
typedef struct _ClutterEventSource ClutterEventSource;
|
||||
@ -172,6 +174,7 @@ _clutter_events_init (ClutterBackend *backend)
|
||||
CLUTTER_NOTE (EVENT, "Connection number: %d", connection_number);
|
||||
|
||||
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);
|
||||
event_source = (ClutterEventSource *) source;
|
||||
@ -211,14 +214,13 @@ _clutter_events_uninit (ClutterBackend *backend)
|
||||
|
||||
|
||||
static void
|
||||
set_user_time (Display *display,
|
||||
Window *xwindow,
|
||||
ClutterEvent *event)
|
||||
set_user_time (Display *display,
|
||||
Window *xwindow,
|
||||
long timestamp)
|
||||
{
|
||||
if (clutter_event_get_time (event) != CLUTTER_CURRENT_TIME)
|
||||
if (timestamp != CLUTTER_CURRENT_TIME)
|
||||
{
|
||||
Atom atom_WM_USER_TIME;
|
||||
long timestamp = clutter_event_get_time (event);
|
||||
|
||||
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 */
|
||||
}
|
||||
|
||||
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,
|
||||
XEvent *xevent)
|
||||
{
|
||||
@ -322,6 +360,9 @@ handle_xembed_event (ClutterBackendGlx *backend_glx,
|
||||
CLUTTER_NOTE (EVENT, "got unknown XEMBED message");
|
||||
break;
|
||||
}
|
||||
|
||||
/* do not propagate the XEMBED events to the stage */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@ -366,7 +407,7 @@ clutter_event_translate (ClutterBackend *backend,
|
||||
case KeyPress:
|
||||
event->type = CLUTTER_KEY_PRESS;
|
||||
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;
|
||||
case KeyRelease:
|
||||
event->type = CLUTTER_KEY_RELEASE;
|
||||
@ -408,7 +449,7 @@ clutter_event_translate (ClutterBackend *backend,
|
||||
break;
|
||||
}
|
||||
|
||||
set_user_time (backend_glx->xdpy, &xwindow, event);
|
||||
set_user_time (backend_glx->xdpy, &xwindow, event->button.time);
|
||||
break;
|
||||
case ButtonRelease:
|
||||
/* scroll events don't have a corresponding release */
|
||||
@ -442,9 +483,16 @@ clutter_event_translate (ClutterBackend *backend,
|
||||
break;
|
||||
case ClientMessage:
|
||||
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;
|
||||
|
||||
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;
|
||||
default:
|
||||
/* 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
|
||||
clutter_stage_glx_realize (ClutterActor *actor)
|
||||
{
|
||||
@ -168,6 +182,8 @@ clutter_stage_glx_realize (ClutterActor *actor)
|
||||
ButtonPressMask | ButtonReleaseMask |
|
||||
PropertyChangeMask);
|
||||
|
||||
set_wm_protocols (stage_glx->xdpy, stage_glx->xwin);
|
||||
|
||||
if (stage_glx->gl_context)
|
||||
glXDestroyContext (stage_glx->xdpy, stage_glx->gl_context);
|
||||
|
||||
|
@ -47,6 +47,7 @@ Windowing events handled by Clutter.
|
||||
</para>
|
||||
|
||||
@CLUTTER_FILTER_CONTINUE:
|
||||
@CLUTTER_FILTER_TRANSLATE:
|
||||
@CLUTTER_FILTER_REMOVE:
|
||||
|
||||
<!-- ##### ENUM ClutterScrollDirection ##### -->
|
||||
@ -86,6 +87,7 @@ Windowing events handled by Clutter.
|
||||
@CLUTTER_STAGE_STATE:
|
||||
@CLUTTER_DESTROY_NOTIFY:
|
||||
@CLUTTER_CLIENT_MESSAGE:
|
||||
@CLUTTER_DELETE:
|
||||
|
||||
<!-- ##### UNION ClutterEvent ##### -->
|
||||
<para>
|
||||
|
Loading…
Reference in New Issue
Block a user