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:
Emmanuele Bassi 2007-04-19 15:26:54 +00:00
parent f1a1399927
commit b2d01d86c2
6 changed files with 94 additions and 29 deletions

View File

@ -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;

View File

@ -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;
}
}

View File

@ -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
*

View File

@ -61,6 +61,8 @@
#define XEMBED_ACTIVATE_ACCELERATOR 14
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;
@ -213,12 +216,11 @@ _clutter_events_uninit (ClutterBackend *backend)
static void
set_user_time (Display *display,
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;
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 */

View File

@ -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);

View File

@ -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>