Blame src/XScrnSaver.c

Packit 0bec48
/*
Packit 0bec48
 *
Packit 0bec48
Copyright (c) 1992  X Consortium
Packit 0bec48
Packit 0bec48
Permission is hereby granted, free of charge, to any person obtaining a copy
Packit 0bec48
of this software and associated documentation files (the "Software"), to deal
Packit 0bec48
in the Software without restriction, including without limitation the rights
Packit 0bec48
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
Packit 0bec48
copies of the Software, and to permit persons to whom the Software is
Packit 0bec48
furnished to do so, subject to the following conditions:
Packit 0bec48
Packit 0bec48
The above copyright notice and this permission notice shall be included in
Packit 0bec48
all copies or substantial portions of the Software.
Packit 0bec48
Packit 0bec48
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
Packit 0bec48
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
Packit 0bec48
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
Packit 0bec48
X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
Packit 0bec48
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
Packit 0bec48
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Packit 0bec48
Packit 0bec48
Except as contained in this notice, the name of the X Consortium shall not be
Packit 0bec48
used in advertising or otherwise to promote the sale, use or other dealings
Packit 0bec48
in this Software without prior written authorization from the X Consortium.
Packit 0bec48
 *
Packit 0bec48
 * Author:  Keith Packard, MIT X Consortium
Packit 0bec48
 */
Packit 0bec48
Packit 0bec48
#include <X11/Xlibint.h>
Packit 0bec48
#include <X11/Xutil.h>
Packit 0bec48
#include <X11/extensions/Xext.h>
Packit 0bec48
#include <X11/extensions/extutil.h>
Packit 0bec48
#include <X11/extensions/saverproto.h>
Packit 0bec48
#include <X11/extensions/scrnsaver.h>
Packit 0bec48
Packit 0bec48
Packit 0bec48
static XExtensionInfo _screen_saver_info_data;
Packit 0bec48
static XExtensionInfo *screen_saver_info = &_screen_saver_info_data;
Packit 0bec48
static const char *screen_saver_extension_name = ScreenSaverName;
Packit 0bec48
Packit 0bec48
#define ScreenSaverCheckExtension(dpy,i,val) \
Packit 0bec48
  XextCheckExtension (dpy, i, screen_saver_extension_name, val)
Packit 0bec48
#define ScreenSaverSimpleCheckExtension(dpy,i) \
Packit 0bec48
  XextSimpleCheckExtension (dpy, i, screen_saver_extension_name)
Packit 0bec48
Packit 0bec48
static int close_display(
Packit 0bec48
    Display *		/* dpy */,
Packit 0bec48
    XExtCodes *		/* codes */
Packit 0bec48
);
Packit 0bec48
Packit 0bec48
static Bool wire_to_event(
Packit 0bec48
    Display *		/* dpy */,
Packit 0bec48
    XEvent *		/* re */,
Packit 0bec48
    xEvent *		/* event */
Packit 0bec48
);
Packit 0bec48
Packit 0bec48
static Status event_to_wire(
Packit 0bec48
    Display *		/* dpy */,
Packit 0bec48
    XEvent *		/* re */,
Packit 0bec48
    xEvent *		/* event */
Packit 0bec48
);
Packit 0bec48
Packit 0bec48
static /* const */ XExtensionHooks screen_saver_extension_hooks = {
Packit 0bec48
    NULL,				/* create_gc */
Packit 0bec48
    NULL,				/* copy_gc */
Packit 0bec48
    NULL,				/* flush_gc */
Packit 0bec48
    NULL,				/* free_gc */
Packit 0bec48
    NULL,				/* create_font */
Packit 0bec48
    NULL,				/* free_font */
Packit 0bec48
    close_display,			/* close_display */
Packit 0bec48
    wire_to_event,			/* wire_to_event */
Packit 0bec48
    event_to_wire,			/* event_to_wire */
Packit 0bec48
    NULL,				/* error */
Packit 0bec48
    NULL,				/* error_string */
Packit 0bec48
};
Packit 0bec48
Packit 0bec48
static XEXT_GENERATE_FIND_DISPLAY (find_display, screen_saver_info,
Packit 0bec48
				   screen_saver_extension_name,
Packit 0bec48
				   &screen_saver_extension_hooks,
Packit 0bec48
				   ScreenSaverNumberEvents, NULL)
Packit 0bec48
Packit 0bec48
static XEXT_GENERATE_CLOSE_DISPLAY (close_display, screen_saver_info)
Packit 0bec48
Packit 0bec48
Packit 0bec48
static Bool wire_to_event (
Packit 0bec48
    Display	*dpy,
Packit 0bec48
    XEvent	*re,
Packit 0bec48
    xEvent	*event)
Packit 0bec48
{
Packit 0bec48
    XExtDisplayInfo *info = find_display (dpy);
Packit 0bec48
    XScreenSaverNotifyEvent	*se;
Packit 0bec48
    xScreenSaverNotifyEvent	*sevent;
Packit 0bec48
Packit 0bec48
    ScreenSaverCheckExtension (dpy, info, False);
Packit 0bec48
Packit 0bec48
    switch ((event->u.u.type & 0x7f) - info->codes->first_event) {
Packit 0bec48
    case ScreenSaverNotify:
Packit 0bec48
    	se = (XScreenSaverNotifyEvent *) re;
Packit 0bec48
	sevent = (xScreenSaverNotifyEvent *) event;
Packit 0bec48
    	se->type = sevent->type & 0x7f;
Packit 0bec48
    	se->serial = _XSetLastRequestRead(dpy,(xGenericReply *) event);
Packit 0bec48
    	se->send_event = (sevent->type & 0x80) != 0;
Packit 0bec48
    	se->display = dpy;
Packit 0bec48
    	se->window = sevent->window;
Packit 0bec48
	se->root = sevent->root;
Packit 0bec48
    	se->state = sevent->state;
Packit 0bec48
	se->kind = sevent->kind;
Packit 0bec48
	se->forced = True;
Packit 0bec48
	if (sevent->forced == xFalse)
Packit 0bec48
	    se->forced = False;
Packit 0bec48
	se->time = sevent->timestamp;
Packit 0bec48
    	return True;
Packit 0bec48
    }
Packit 0bec48
    return False;
Packit 0bec48
}
Packit 0bec48
Packit 0bec48
static Status event_to_wire (
Packit 0bec48
    Display	*dpy,
Packit 0bec48
    XEvent	*re,
Packit 0bec48
    xEvent	*event)
Packit 0bec48
{
Packit 0bec48
    XExtDisplayInfo *info = find_display (dpy);
Packit 0bec48
    XScreenSaverNotifyEvent	*se;
Packit 0bec48
    xScreenSaverNotifyEvent	*sevent;
Packit 0bec48
Packit 0bec48
    ScreenSaverCheckExtension (dpy, info, 0);
Packit 0bec48
Packit 0bec48
    switch ((re->type & 0x7f) - info->codes->first_event) {
Packit 0bec48
    case ScreenSaverNotify:
Packit 0bec48
    	se = (XScreenSaverNotifyEvent *) re;
Packit 0bec48
	sevent = (xScreenSaverNotifyEvent *) event;
Packit 0bec48
    	sevent->type = se->type | (se->send_event ? 0x80 : 0);
Packit 0bec48
    	sevent->sequenceNumber = se->serial & 0xffff;
Packit 0bec48
    	sevent->root = se->root;
Packit 0bec48
    	sevent->window = se->window;
Packit 0bec48
    	sevent->state = se->state;
Packit 0bec48
	sevent->kind = se->kind;
Packit 0bec48
	sevent->forced = xFalse;
Packit 0bec48
	if (se->forced == True)
Packit 0bec48
	    sevent->forced = xTrue;
Packit 0bec48
	sevent->timestamp = se->time;
Packit 0bec48
    	return 1;
Packit 0bec48
    }
Packit 0bec48
    return 0;
Packit 0bec48
}
Packit 0bec48
Packit 0bec48
/****************************************************************************
Packit 0bec48
 *                                                                          *
Packit 0bec48
 *			    ScreenSaver public interfaces                         *
Packit 0bec48
 *                                                                          *
Packit 0bec48
 ****************************************************************************/
Packit 0bec48
Packit 0bec48
Bool XScreenSaverQueryExtension (
Packit 0bec48
    Display	*dpy,
Packit 0bec48
    int		*event_base_return,
Packit 0bec48
    int		*error_base_return)
Packit 0bec48
{
Packit 0bec48
    XExtDisplayInfo *info = find_display (dpy);
Packit 0bec48
Packit 0bec48
    if (XextHasExtension(info)) {
Packit 0bec48
	*event_base_return = info->codes->first_event;
Packit 0bec48
	*error_base_return = info->codes->first_error;
Packit 0bec48
	return True;
Packit 0bec48
    } else {
Packit 0bec48
	return False;
Packit 0bec48
    }
Packit 0bec48
}
Packit 0bec48
Packit 0bec48
Packit 0bec48
Status XScreenSaverQueryVersion(
Packit 0bec48
    Display	*dpy,
Packit 0bec48
    int		*major_version_return,
Packit 0bec48
    int		*minor_version_return)
Packit 0bec48
{
Packit 0bec48
    XExtDisplayInfo *info = find_display (dpy);
Packit 0bec48
    xScreenSaverQueryVersionReply	    rep;
Packit 0bec48
    register xScreenSaverQueryVersionReq  *req;
Packit 0bec48
Packit 0bec48
    ScreenSaverCheckExtension (dpy, info, 0);
Packit 0bec48
Packit 0bec48
    LockDisplay (dpy);
Packit 0bec48
    GetReq (ScreenSaverQueryVersion, req);
Packit 0bec48
    req->reqType = info->codes->major_opcode;
Packit 0bec48
    req->saverReqType = X_ScreenSaverQueryVersion;
Packit 0bec48
    req->clientMajor = ScreenSaverMajorVersion;
Packit 0bec48
    req->clientMinor = ScreenSaverMinorVersion;
Packit 0bec48
    if (!_XReply (dpy, (xReply *) &rep, 0, xTrue)) {
Packit 0bec48
	UnlockDisplay (dpy);
Packit 0bec48
	SyncHandle ();
Packit 0bec48
	return 0;
Packit 0bec48
    }
Packit 0bec48
    *major_version_return = rep.majorVersion;
Packit 0bec48
    *minor_version_return = rep.minorVersion;
Packit 0bec48
    UnlockDisplay (dpy);
Packit 0bec48
    SyncHandle ();
Packit 0bec48
    return 1;
Packit 0bec48
}
Packit 0bec48
Packit 0bec48
XScreenSaverInfo *XScreenSaverAllocInfo (void)
Packit 0bec48
{
Packit 0bec48
    return (XScreenSaverInfo *) Xmalloc (sizeof (XScreenSaverInfo));
Packit 0bec48
}
Packit 0bec48
Packit 0bec48
Status XScreenSaverQueryInfo (
Packit 0bec48
    Display		*dpy,
Packit 0bec48
    Drawable		 drawable,
Packit 0bec48
    XScreenSaverInfo	*saver_info)
Packit 0bec48
{
Packit 0bec48
    XExtDisplayInfo			*info = find_display (dpy);
Packit 0bec48
    xScreenSaverQueryInfoReply		rep;
Packit 0bec48
    register xScreenSaverQueryInfoReq	*req;
Packit 0bec48
Packit 0bec48
    ScreenSaverCheckExtension (dpy, info, 0);
Packit 0bec48
Packit 0bec48
    LockDisplay (dpy);
Packit 0bec48
    GetReq (ScreenSaverQueryInfo, req);
Packit 0bec48
    req->reqType = info->codes->major_opcode;
Packit 0bec48
    req->saverReqType = X_ScreenSaverQueryInfo;
Packit 0bec48
    req->drawable = drawable;
Packit 0bec48
    if (!_XReply (dpy, (xReply *) &rep, 0, xTrue)) {
Packit 0bec48
	UnlockDisplay (dpy);
Packit 0bec48
	SyncHandle ();
Packit 0bec48
	return 0;
Packit 0bec48
    }
Packit 0bec48
    UnlockDisplay (dpy);
Packit 0bec48
    SyncHandle ();
Packit 0bec48
    saver_info->window = rep.window;
Packit 0bec48
    saver_info->state = rep.state;
Packit 0bec48
    saver_info->kind = rep.kind;
Packit 0bec48
    saver_info->til_or_since = rep.tilOrSince;
Packit 0bec48
    saver_info->idle = rep.idle;
Packit 0bec48
    saver_info->eventMask = rep.eventMask;
Packit 0bec48
    return 1;
Packit 0bec48
}
Packit 0bec48
Packit 0bec48
void XScreenSaverSelectInput (
Packit 0bec48
    register Display	*dpy,
Packit 0bec48
    Drawable		 drawable,
Packit 0bec48
    unsigned long	 mask)
Packit 0bec48
{
Packit 0bec48
    XExtDisplayInfo *info = find_display (dpy);
Packit 0bec48
    register xScreenSaverSelectInputReq   *req;
Packit 0bec48
Packit 0bec48
    ScreenSaverSimpleCheckExtension (dpy, info);
Packit 0bec48
Packit 0bec48
    LockDisplay (dpy);
Packit 0bec48
    GetReq (ScreenSaverSelectInput, req);
Packit 0bec48
    req->reqType = info->codes->major_opcode;
Packit 0bec48
    req->saverReqType = X_ScreenSaverSelectInput;
Packit 0bec48
    req->drawable = drawable;
Packit 0bec48
    req->eventMask = mask;
Packit 0bec48
    UnlockDisplay (dpy);
Packit 0bec48
    SyncHandle ();
Packit 0bec48
}
Packit 0bec48
Packit 0bec48
static void
Packit 0bec48
XScreenSaverProcessWindowAttributes (
Packit 0bec48
    register Display			*dpy,
Packit 0bec48
    xChangeWindowAttributesReq		*req,
Packit 0bec48
    register unsigned long		 valuemask,
Packit 0bec48
    register XSetWindowAttributes	*attributes)
Packit 0bec48
    {
Packit 0bec48
    unsigned long values[32];
Packit 0bec48
    register unsigned long *value = values;
Packit 0bec48
    unsigned int nvalues;
Packit 0bec48
Packit 0bec48
    if (valuemask & CWBackPixmap)
Packit 0bec48
	*value++ = attributes->background_pixmap;
Packit 0bec48
Packit 0bec48
    if (valuemask & CWBackPixel)
Packit 0bec48
    	*value++ = attributes->background_pixel;
Packit 0bec48
Packit 0bec48
    if (valuemask & CWBorderPixmap)
Packit 0bec48
    	*value++ = attributes->border_pixmap;
Packit 0bec48
Packit 0bec48
    if (valuemask & CWBorderPixel)
Packit 0bec48
    	*value++ = attributes->border_pixel;
Packit 0bec48
Packit 0bec48
    if (valuemask & CWBitGravity)
Packit 0bec48
    	*value++ = attributes->bit_gravity;
Packit 0bec48
Packit 0bec48
    if (valuemask & CWWinGravity)
Packit 0bec48
	*value++ = attributes->win_gravity;
Packit 0bec48
Packit 0bec48
    if (valuemask & CWBackingStore)
Packit 0bec48
        *value++ = attributes->backing_store;
Packit 0bec48
Packit 0bec48
    if (valuemask & CWBackingPlanes)
Packit 0bec48
	*value++ = attributes->backing_planes;
Packit 0bec48
Packit 0bec48
    if (valuemask & CWBackingPixel)
Packit 0bec48
    	*value++ = attributes->backing_pixel;
Packit 0bec48
Packit 0bec48
    if (valuemask & CWOverrideRedirect)
Packit 0bec48
    	*value++ = attributes->override_redirect;
Packit 0bec48
Packit 0bec48
    if (valuemask & CWSaveUnder)
Packit 0bec48
    	*value++ = attributes->save_under;
Packit 0bec48
Packit 0bec48
    if (valuemask & CWEventMask)
Packit 0bec48
	*value++ = attributes->event_mask;
Packit 0bec48
Packit 0bec48
    if (valuemask & CWDontPropagate)
Packit 0bec48
	*value++ = attributes->do_not_propagate_mask;
Packit 0bec48
Packit 0bec48
    if (valuemask & CWColormap)
Packit 0bec48
	*value++ = attributes->colormap;
Packit 0bec48
Packit 0bec48
    if (valuemask & CWCursor)
Packit 0bec48
	*value++ = attributes->cursor;
Packit 0bec48
Packit 0bec48
    req->length += (nvalues = value - values);
Packit 0bec48
Packit 0bec48
    nvalues <<= 2;			    /* watch out for macros... */
Packit 0bec48
    Data32 (dpy, (long *) values, (long)nvalues);
Packit 0bec48
Packit 0bec48
    }
Packit 0bec48
Packit 0bec48
void XScreenSaverSetAttributes (
Packit 0bec48
    Display			*dpy,
Packit 0bec48
    Drawable			 drawable,
Packit 0bec48
    int				 x,
Packit 0bec48
    int				 y,
Packit 0bec48
    unsigned int		 width,
Packit 0bec48
    unsigned int		 height,
Packit 0bec48
    unsigned int		 border_width,
Packit 0bec48
    int				 depth,
Packit 0bec48
    unsigned int		 class,
Packit 0bec48
    Visual			*visual,
Packit 0bec48
    unsigned long		 valuemask,
Packit 0bec48
    XSetWindowAttributes	*attributes)
Packit 0bec48
{
Packit 0bec48
    XExtDisplayInfo *info = find_display (dpy);
Packit 0bec48
    register xScreenSaverSetAttributesReq   *req;
Packit 0bec48
Packit 0bec48
    ScreenSaverSimpleCheckExtension (dpy, info);
Packit 0bec48
Packit 0bec48
    LockDisplay (dpy);
Packit 0bec48
    GetReq (ScreenSaverSetAttributes, req);
Packit 0bec48
    req->reqType = info->codes->major_opcode;
Packit 0bec48
    req->saverReqType = X_ScreenSaverSetAttributes;
Packit 0bec48
    req->drawable = drawable;
Packit 0bec48
    req->x = x;
Packit 0bec48
    req->y = y;
Packit 0bec48
    req->width = width;
Packit 0bec48
    req->height = height;
Packit 0bec48
    req->borderWidth = border_width;
Packit 0bec48
    req->c_class = class;
Packit 0bec48
    req->depth = depth;
Packit 0bec48
    if (visual == (Visual *)CopyFromParent)
Packit 0bec48
	req->visualID = CopyFromParent;
Packit 0bec48
    else
Packit 0bec48
	req->visualID = visual->visualid;
Packit 0bec48
    /* abuse an Xlib internal interface - is this legal for us? */
Packit 0bec48
    if ((req->mask = valuemask))
Packit 0bec48
        XScreenSaverProcessWindowAttributes (dpy,
Packit 0bec48
			(xChangeWindowAttributesReq *)req,
Packit 0bec48
			valuemask, attributes);
Packit 0bec48
    UnlockDisplay (dpy);
Packit 0bec48
    SyncHandle ();
Packit 0bec48
}
Packit 0bec48
Packit 0bec48
Packit 0bec48
void XScreenSaverUnsetAttributes (
Packit 0bec48
    register Display	*dpy,
Packit 0bec48
    Drawable		 drawable)
Packit 0bec48
{
Packit 0bec48
    XExtDisplayInfo *info = find_display (dpy);
Packit 0bec48
    register xScreenSaverUnsetAttributesReq   *req;
Packit 0bec48
Packit 0bec48
    ScreenSaverSimpleCheckExtension (dpy, info);
Packit 0bec48
Packit 0bec48
    LockDisplay (dpy);
Packit 0bec48
    GetReq (ScreenSaverUnsetAttributes, req);
Packit 0bec48
    req->reqType = info->codes->major_opcode;
Packit 0bec48
    req->saverReqType = X_ScreenSaverUnsetAttributes;
Packit 0bec48
    req->drawable = drawable;
Packit 0bec48
    UnlockDisplay (dpy);
Packit 0bec48
    SyncHandle ();
Packit 0bec48
}
Packit 0bec48
Packit 0bec48
Packit 0bec48
Status XScreenSaverRegister (
Packit 0bec48
    Display	*dpy,
Packit 0bec48
    int		 screen,
Packit 0bec48
    XID		 xid,
Packit 0bec48
    Atom	 type)
Packit 0bec48
{
Packit 0bec48
    Atom prop;
Packit 0bec48
    unsigned long ul;
Packit 0bec48
Packit 0bec48
    prop = XInternAtom (dpy, ScreenSaverPropertyName, False);
Packit 0bec48
    if (!prop)
Packit 0bec48
	return 0;
Packit 0bec48
Packit 0bec48
    ul = (unsigned long) xid;
Packit 0bec48
    XChangeProperty (dpy, RootWindow(dpy,screen), prop, type, 32,
Packit 0bec48
		     PropModeReplace, (unsigned char *) &ul, 1);
Packit 0bec48
    return 1;
Packit 0bec48
}
Packit 0bec48
Packit 0bec48
Packit 0bec48
Packit 0bec48
Status XScreenSaverUnregister (
Packit 0bec48
    Display	*dpy,
Packit 0bec48
    int		 screen)
Packit 0bec48
{
Packit 0bec48
    Atom prop;
Packit 0bec48
Packit 0bec48
    prop = XInternAtom (dpy, ScreenSaverPropertyName, False);
Packit 0bec48
    if (!prop)
Packit 0bec48
	return 0;
Packit 0bec48
Packit 0bec48
    XDeleteProperty (dpy, RootWindow(dpy,screen), prop);
Packit 0bec48
    return 1;
Packit 0bec48
}
Packit 0bec48
Packit 0bec48
Packit 0bec48
Packit 0bec48
Status XScreenSaverGetRegistered (
Packit 0bec48
    Display	*dpy,
Packit 0bec48
    int		 screen,
Packit 0bec48
    XID		*xid,
Packit 0bec48
    Atom	*type)
Packit 0bec48
{
Packit 0bec48
    Atom actual_type = None;
Packit 0bec48
    int actual_format;
Packit 0bec48
    unsigned long nitems, bytesafter;
Packit 0bec48
    unsigned long *ulp = (unsigned long *) 0;
Packit 0bec48
    Atom prop;
Packit 0bec48
    int retval = 0;
Packit 0bec48
Packit 0bec48
    prop = XInternAtom (dpy, ScreenSaverPropertyName, False);
Packit 0bec48
    if (!prop)
Packit 0bec48
	return retval;
Packit 0bec48
Packit 0bec48
    if (XGetWindowProperty (dpy, RootWindow(dpy,screen), prop, 0L, 1L, False,
Packit 0bec48
			    AnyPropertyType, &actual_type,  &actual_format,
Packit 0bec48
			    &nitems, &bytesafter, (unsigned char **) &ulp)
Packit 0bec48
	!= Success)
Packit 0bec48
	return retval;
Packit 0bec48
Packit 0bec48
    if (ulp) {
Packit 0bec48
	if (actual_format == 32) {
Packit 0bec48
	    *xid = (XID) ulp[0];
Packit 0bec48
	    *type = actual_type;
Packit 0bec48
	    retval = 1;
Packit 0bec48
	}
Packit 0bec48
	XFree ((char *) ulp);
Packit 0bec48
    }
Packit 0bec48
    return retval;
Packit 0bec48
}
Packit 0bec48
Packit 0bec48
void
Packit 0bec48
XScreenSaverSuspend (Display *dpy, Bool suspend)
Packit 0bec48
{
Packit 0bec48
    XExtDisplayInfo *info = find_display (dpy);
Packit 0bec48
    xScreenSaverSuspendReq   *req;
Packit 0bec48
Packit 0bec48
    ScreenSaverSimpleCheckExtension (dpy, info);
Packit 0bec48
Packit 0bec48
    LockDisplay (dpy);
Packit 0bec48
    GetReq (ScreenSaverSuspend, req);
Packit 0bec48
    req->reqType = info->codes->major_opcode;
Packit 0bec48
    req->saverReqType = X_ScreenSaverSuspend;
Packit 0bec48
    req->suspend = suspend;
Packit 0bec48
    UnlockDisplay (dpy);
Packit 0bec48
    SyncHandle ();
Packit 0bec48
}
Packit 0bec48