Tk
view release on metacpan or search on metacpan
pTk/mTk/unix/tkUnixWm.c view on Meta::CPAN
}
#ifdef _LANG
Tcl_IncrRefCount(objv[3]);
/* Free the old one */
TkWmFreeCmd(wmPtr);
/* Save reference to new one to keep strings live */
wmPtr->cmdArg = objv[3];
#else
if (wmPtr->cmdArgv != NULL) {
ckfree((char *) wmPtr->cmdArgv);
}
wmPtr->cmdArgc = cmdArgc;
wmPtr->cmdArgv = (CONST char **) ckalloc(cmdArgc*sizeof(char *));
for (i=0; i < cmdArgc; i++)
{
wmPtr->cmdArgv[i] = Tcl_GetString(cmdArgv[i]);
}
#endif
if (!(wmPtr->flags & WM_NEVER_MAPPED)) {
UpdateCommand(winPtr);
}
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* WmDeiconifyCmd --
*
* This function is invoked to process the "wm deiconify" Tcl command.
* See the user documentation for details on what it does.
*
* Results:
* A standard Tcl result.
*
* Side effects:
* See the user documentation.
*
*----------------------------------------------------------------------
*/
static int
WmDeiconifyCmd(
Tk_Window tkwin, /* Main window of the application. */
TkWindow *winPtr, /* Toplevel to work with */
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *CONST objv[]) /* Argument objects. */
{
register WmInfo *wmPtr = winPtr->wmInfoPtr;
if (objc != 3) {
Tcl_WrongNumArgs(interp, 2, objv, "window");
return TCL_ERROR;
}
if (wmPtr->iconFor != NULL) {
Tcl_AppendResult(interp, "can't deiconify ", Tcl_GetString(objv[2]),
": it is an icon for ", Tk_PathName(wmPtr->iconFor), NULL);
return TCL_ERROR;
}
if (winPtr->flags & TK_EMBEDDED) {
Tcl_AppendResult(interp, "can't deiconify ", winPtr->pathName,
": it is an embedded window", NULL);
return TCL_ERROR;
}
wmPtr->flags &= ~WM_WITHDRAWN;
TkpWmSetState(winPtr, NormalState);
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* WmFocusmodelCmd --
*
* This function is invoked to process the "wm focusmodel" Tcl command.
* See the user documentation for details on what it does.
*
* Results:
* A standard Tcl result.
*
* Side effects:
* See the user documentation.
*
*----------------------------------------------------------------------
*/
static int
WmFocusmodelCmd(
Tk_Window tkwin, /* Main window of the application. */
TkWindow *winPtr, /* Toplevel to work with */
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *CONST objv[]) /* Argument objects. */
{
register WmInfo *wmPtr = winPtr->wmInfoPtr;
static CONST char *optionStrings[] = {
"active", "passive", NULL };
enum options {
OPT_ACTIVE, OPT_PASSIVE };
int index;
if ((objc != 3) && (objc != 4)) {
Tcl_WrongNumArgs(interp, 2, objv, "window ?active|passive?");
return TCL_ERROR;
}
if (objc == 3) {
Tcl_SetResult(interp, (wmPtr->hints.input ? "passive" : "active"),
TCL_STATIC);
return TCL_OK;
}
if (Tcl_GetIndexFromObj(interp, objv[3], optionStrings, "argument", 0,
&index) != TCL_OK) {
return TCL_ERROR;
}
if (index == OPT_ACTIVE) {
wmPtr->hints.input = False;
} else { /* OPT_PASSIVE */
wmPtr->hints.input = True;
}
pTk/mTk/unix/tkUnixWm.c view on Meta::CPAN
wmPtr->hints.icon_pixmap = None;
}
wmPtr->hints.flags &= ~IconPixmapHint;
} else {
pixmap = Tk_GetBitmap(interp, (Tk_Window) winPtr, argv3);
if (pixmap == None) {
return TCL_ERROR;
}
wmPtr->hints.icon_pixmap = pixmap;
wmPtr->hints.flags |= IconPixmapHint;
}
UpdateHints(winPtr);
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* WmIconifyCmd --
*
* This function is invoked to process the "wm iconify" Tcl command. See
* the user documentation for details on what it does.
*
* Results:
* A standard Tcl result.
*
* Side effects:
* See the user documentation.
*
*----------------------------------------------------------------------
*/
static int
WmIconifyCmd(
Tk_Window tkwin, /* Main window of the application. */
TkWindow *winPtr, /* Toplevel to work with */
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *CONST objv[]) /* Argument objects. */
{
register WmInfo *wmPtr = winPtr->wmInfoPtr;
if (objc != 3) {
Tcl_WrongNumArgs(interp, 2, objv, "window");
return TCL_ERROR;
}
if (Tk_Attributes((Tk_Window) winPtr)->override_redirect) {
Tcl_AppendResult(interp, "can't iconify \"", winPtr->pathName,
"\": override-redirect flag is set", NULL);
return TCL_ERROR;
}
if (wmPtr->masterPtr != NULL) {
Tcl_AppendResult(interp, "can't iconify \"", winPtr->pathName,
"\": it is a transient", NULL);
return TCL_ERROR;
}
if (wmPtr->iconFor != NULL) {
Tcl_AppendResult(interp, "can't iconify ", winPtr->pathName,
": it is an icon for ", Tk_PathName(wmPtr->iconFor), NULL);
return TCL_ERROR;
}
if (winPtr->flags & TK_EMBEDDED) {
Tcl_AppendResult(interp, "can't iconify ", winPtr->pathName,
": it is an embedded window", NULL);
return TCL_ERROR;
}
if (TkpWmSetState(winPtr, IconicState) == 0) {
Tcl_SetResult(interp,
"couldn't send iconify message to window manager",
TCL_STATIC);
return TCL_ERROR;
}
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* WmIconmaskCmd --
*
* This function is invoked to process the "wm iconmask" Tcl command.
* See the user documentation for details on what it does.
*
* Results:
* A standard Tcl result.
*
* Side effects:
* See the user documentation.
*
*----------------------------------------------------------------------
*/
static int
WmIconmaskCmd(
Tk_Window tkwin, /* Main window of the application. */
TkWindow *winPtr, /* Toplevel to work with */
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *CONST objv[]) /* Argument objects. */
{
register WmInfo *wmPtr = winPtr->wmInfoPtr;
Pixmap pixmap;
char *argv3;
if ((objc != 3) && (objc != 4)) {
Tcl_WrongNumArgs(interp, 2, objv, "window ?bitmap?");
return TCL_ERROR;
}
if (objc == 3) {
if (wmPtr->hints.flags & IconMaskHint) {
Tcl_SetResult(interp, (char *)
Tk_NameOfBitmap(winPtr->display, wmPtr->hints.icon_mask),
TCL_STATIC);
}
return TCL_OK;
}
argv3 = Tcl_GetString(objv[3]);
if (*argv3 == '\0') {
if (wmPtr->hints.icon_mask != None) {
Tk_FreeBitmap(winPtr->display, wmPtr->hints.icon_mask);
}
wmPtr->hints.flags &= ~IconMaskHint;
pTk/mTk/unix/tkUnixWm.c view on Meta::CPAN
*
* Results:
* None.
*
* Side effects:
* Information gets updated in the WmInfo structure for the window and
* the toplevel itself gets repositioned within the wrapper.
*
*----------------------------------------------------------------------
*/
static void
ConfigureEvent(
WmInfo *wmPtr, /* Information about toplevel window. */
XConfigureEvent *configEventPtr)
/* Event that just occurred for
* wmPtr->wrapperPtr. */
{
TkWindow *wrapperPtr = wmPtr->wrapperPtr;
TkWindow *winPtr = wmPtr->winPtr;
TkDisplay *dispPtr = wmPtr->winPtr->dispPtr;
Tk_ErrorHandler handler;
/*
* Update size information from the event. There are a couple of tricky
* points here:
*
* 1. If the user changed the size externally then set wmPtr->width and
* wmPtr->height just as if a "wm geometry" command had been invoked
* with the same information.
* 2. However, if the size is changing in response to a request coming
* from us (WM_SYNC_PENDING is set), then don't set wmPtr->width or
* wmPtr->height if they were previously -1 (otherwise the window will
* stop tracking geometry manager requests).
*/
if (((wrapperPtr->changes.width != configEventPtr->width)
|| (wrapperPtr->changes.height != configEventPtr->height))
&& !(wmPtr->flags & WM_SYNC_PENDING)) {
if (dispPtr->flags & TK_DISPLAY_WM_TRACING) {
printf("TopLevelEventProc: user changed %s size to %dx%d\n",
winPtr->pathName, configEventPtr->width,
configEventPtr->height);
}
if ((wmPtr->width == -1)
&& (configEventPtr->width == winPtr->reqWidth)) {
/*
* Don't set external width, since the user didn't change it from
* what the widgets asked for.
*/
} else {
/*
* Note: if this window is embedded then don't set the external
* size, since it came from the containing application, not the
* user. In this case we want to keep sending our size requests to
* the containing application; if the user fixes the size of that
* application then it will still percolate down to us in the
* right way.
*/
if (!(winPtr->flags & TK_EMBEDDED)) {
if (wmPtr->gridWin != NULL) {
wmPtr->width = wmPtr->reqGridWidth
+ (configEventPtr->width
- winPtr->reqWidth)/wmPtr->widthInc;
if (wmPtr->width < 0) {
wmPtr->width = 0;
}
} else {
wmPtr->width = configEventPtr->width;
}
}
}
if ((wmPtr->height == -1)
&& (configEventPtr->height ==
(winPtr->reqHeight + wmPtr->menuHeight))) {
/*
* Don't set external height, since the user didn't change it from
* what the widgets asked for.
*/
} else {
/*
* See note for wmPtr->width about not setting external size for
* embedded windows.
*/
if (!(winPtr->flags & TK_EMBEDDED)) {
if (wmPtr->gridWin != NULL) {
wmPtr->height = wmPtr->reqGridHeight
+ (configEventPtr->height - wmPtr->menuHeight
- winPtr->reqHeight)/wmPtr->heightInc;
if (wmPtr->height < 0) {
wmPtr->height = 0;
}
} else {
wmPtr->height = configEventPtr->height - wmPtr->menuHeight;
}
}
}
wmPtr->configWidth = configEventPtr->width;
wmPtr->configHeight = configEventPtr->height;
}
if (dispPtr->flags & TK_DISPLAY_WM_TRACING) {
printf("ConfigureEvent: %s x = %d y = %d, width = %d, height = %d\n",
winPtr->pathName, configEventPtr->x, configEventPtr->y,
configEventPtr->width, configEventPtr->height);
printf(" send_event = %d, serial = %ld (win %p, wrapper %p)\n",
configEventPtr->send_event, configEventPtr->serial,
winPtr, wrapperPtr);
}
wrapperPtr->changes.width = configEventPtr->width;
wrapperPtr->changes.height = configEventPtr->height;
wrapperPtr->changes.border_width = configEventPtr->border_width;
wrapperPtr->changes.sibling = configEventPtr->above;
wrapperPtr->changes.stack_mode = Above;
/*
* Reparenting window managers make life difficult. If the window manager
* reparents a top-level window then the x and y information that comes in
* events for the window is wrong: it gives the location of the window
* inside its decorative parent, rather than the location of the window in
* root coordinates, which is what we want. Window managers are supposed
* to send synthetic events with the correct information, but ICCCM
* doesn't require them to do this under all conditions, and the
* information provided doesn't include everything we need here. So, the
* code below maintains a bunch of information about the parent window.
* If the window hasn't been reparented, we pretend that there is a parent
* shrink-wrapped around the window.
*/
if (dispPtr->flags & TK_DISPLAY_WM_TRACING) {
printf(" %s parent == %p, above %p\n",
winPtr->pathName, (void *) wmPtr->reparent,
(void *) configEventPtr->above);
}
if ((wmPtr->reparent == None) || !ComputeReparentGeometry(wmPtr)) {
wmPtr->parentWidth = configEventPtr->width
+ 2*configEventPtr->border_width;
wmPtr->parentHeight = configEventPtr->height
+ 2*configEventPtr->border_width;
wrapperPtr->changes.x = wmPtr->x = configEventPtr->x;
wrapperPtr->changes.y = wmPtr->y = configEventPtr->y;
if (wmPtr->flags & WM_NEGATIVE_X) {
wmPtr->x = wmPtr->vRootWidth - (wmPtr->x + wmPtr->parentWidth);
}
pTk/mTk/unix/tkUnixWm.c view on Meta::CPAN
/*
* Compute the new position for the upper-left pixel of the window's
* decorative frame. This is tricky, because we need to include the border
* widths supplied by a reparented parent in this calculation, but can't
* use the parent's current overall size since that may change as a result
* of this code.
*/
if (wmPtr->flags & WM_NEGATIVE_X) {
x = wmPtr->vRootWidth - wmPtr->x
- (width + (wmPtr->parentWidth - winPtr->changes.width));
} else {
x = wmPtr->x;
}
if (wmPtr->flags & WM_NEGATIVE_Y) {
y = wmPtr->vRootHeight - wmPtr->y
- (height + (wmPtr->parentHeight - winPtr->changes.height));
} else {
y = wmPtr->y;
}
/*
* If the window's size is going to change and the window is supposed to
* not be resizable by the user, then we have to update the size hints.
* There may also be a size-hint-update request pending from somewhere
* else, too.
*/
if (((width != winPtr->changes.width)
|| (height != winPtr->changes.height))
&& (wmPtr->gridWin == NULL)
&& ((wmPtr->sizeHintsFlags & (PMinSize|PMaxSize)) == 0)) {
wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
}
if (wmPtr->flags & WM_UPDATE_SIZE_HINTS) {
UpdateSizeHints(winPtr, width, height);
}
/*
* Reconfigure the wrapper if it isn't already configured correctly. A few
* tricky points:
*
* 1. If the window is embeddedand the container is also in this process,
* don't actually reconfigure the window; just pass the desired size on
* to the container. Also, zero out any position information, since
* embedded windows are not allowed to move.
* 2. Sometimes the window manager will give us a different size than we
* asked for (e.g. mwm has a minimum size for windows), so base the
* size check on what we *asked for* last time, not what we got.
* 3. Can't just reconfigure always, because we may not get a
* ConfigureNotify event back if nothing changed, so
* WaitForConfigureNotify will hang a long time.
* 4. Don't move window unless a new position has been requested for it.
* This is because of "features" in some window managers (e.g. twm, as
* of 4/24/91) where they don't interpret coordinates according to
* ICCCM. Moving a window to its current location may cause it to shift
* position on the screen.
*/
if ((winPtr->flags & (TK_EMBEDDED|TK_BOTH_HALVES))
== (TK_EMBEDDED|TK_BOTH_HALVES)) {
TkWindow *childPtr = TkpGetOtherWindow(winPtr);
/*
* This window is embedded and the container is also in this process,
* so we don't need to do anything special about the geometry, except
* to make sure that the desired size is known by the container. Also,
* zero out any position information, since embedded windows are not
* allowed to move.
*/
wmPtr->x = wmPtr->y = 0;
wmPtr->flags &= ~(WM_NEGATIVE_X|WM_NEGATIVE_Y);
height += wmPtr->menuHeight;
if (childPtr != NULL) {
Tk_GeometryRequest((Tk_Window) childPtr, width, height);
}
return;
}
serial = NextRequest(winPtr->display);
height += wmPtr->menuHeight;
if (wmPtr->flags & WM_MOVE_PENDING) {
if ((x + wmPtr->xInParent == winPtr->changes.x) &&
(y + wmPtr->yInParent + wmPtr->menuHeight == winPtr->changes.y)
&& (width == wmPtr->wrapperPtr->changes.width)
&& (height == wmPtr->wrapperPtr->changes.height)) {
/*
* The window already has the correct geometry, so don't bother to
* configure it; the X server appears to ignore these requests, so
* we won't get back a ConfigureNotify and the
* WaitForConfigureNotify call below will hang for a while.
*/
wmPtr->flags &= ~WM_MOVE_PENDING;
return;
}
wmPtr->configWidth = width;
wmPtr->configHeight = height;
if (winPtr->dispPtr->flags & TK_DISPLAY_WM_TRACING) {
printf("UpdateGeometryInfo moving to %d %d, resizing to %dx%d,\n",
x, y, width, height);
}
XMoveResizeWindow(winPtr->display, wmPtr->wrapperPtr->window, x, y,
(unsigned) width, (unsigned) height);
} else if ((width != wmPtr->configWidth)
|| (height != wmPtr->configHeight)) {
if ((width == wmPtr->wrapperPtr->changes.width)
&& (height == wmPtr->wrapperPtr->changes.height)) {
/*
* The window is already just the size we want, so don't bother to
* configure it; the X server appears to ignore these requests, so
* we won't get back a ConfigureNotify and the
* WaitForConfigureNotify call below will hang for a while.
*/
return;
}
wmPtr->configWidth = width;
wmPtr->configHeight = height;
if (winPtr->dispPtr->flags & TK_DISPLAY_WM_TRACING) {
printf("UpdateGeometryInfo resizing %p to %d x %d\n",
pTk/mTk/unix/tkUnixWm.c view on Meta::CPAN
}
return TCL_OK;
error:
Tcl_AppendResult(interp, "bad geometry specifier \"", string, "\"", NULL);
return TCL_ERROR;
}
/*
*----------------------------------------------------------------------
*
* Tk_GetRootCoords --
*
* Given a token for a window, this function traces through the window's
* lineage to find the (virtual) root-window coordinates corresponding to
* point (0,0) in the window.
*
* Results:
* The locations pointed to by xPtr and yPtr are filled in with the root
* coordinates of the (0,0) point in tkwin. If a virtual root window is
* in effect for the window, then the coordinates in the virtual root are
* returned.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
void
Tk_GetRootCoords(
Tk_Window tkwin, /* Token for window. */
int *xPtr, /* Where to store x-displacement of (0,0). */
int *yPtr) /* Where to store y-displacement of (0,0). */
{
int x, y;
register TkWindow *winPtr = (TkWindow *) tkwin;
/*
* Search back through this window's parents all the way to a top-level
* window, combining the offsets of each window within its parent.
*/
x = y = 0;
while (1) {
x += winPtr->changes.x + winPtr->changes.border_width;
y += winPtr->changes.y + winPtr->changes.border_width;
if ((winPtr->wmInfoPtr != NULL)
&& (winPtr->wmInfoPtr->menubar == (Tk_Window) winPtr)) {
/*
* This window is a special menubar; switch over to its associated
* toplevel, compensate for their differences in y coordinates,
* then continue with the toplevel (in case it's embedded).
*/
y -= winPtr->wmInfoPtr->menuHeight;
winPtr = winPtr->wmInfoPtr->winPtr;
continue;
}
if (winPtr->flags & TK_TOP_LEVEL) {
TkWindow *otherPtr;
if (!(winPtr->flags & TK_EMBEDDED)) {
break;
}
otherPtr = TkpGetOtherWindow(winPtr);
if (otherPtr == NULL) {
/*
* The container window is not in the same application. Query
* the X server.
*/
Window root, dummyChild;
int rootX, rootY;
root = winPtr->wmInfoPtr->vRoot;
if (root == None) {
root = RootWindowOfScreen(Tk_Screen((Tk_Window)winPtr));
}
XTranslateCoordinates(winPtr->display, winPtr->window,
root, 0, 0, &rootX, &rootY, &dummyChild);
x += rootX;
y += rootY;
break;
} else {
/*
* The container window is in the same application. Let's
* query its coordinates.
*/
winPtr = otherPtr;
continue;
}
}
winPtr = winPtr->parentPtr;
if (winPtr == NULL) {
break;
}
}
*xPtr = x;
*yPtr = y;
}
/*
*----------------------------------------------------------------------
*
* Tk_CoordsToWindow --
*
* Given the (virtual) root coordinates of a point, this function returns
* the token for the top-most window covering that point, if there exists
* such a window in this application.
*
* Results:
* The return result is either a token for the window corresponding to
* rootX and rootY, or else NULL to indicate that there is no such
* window.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
pTk/mTk/unix/tkUnixWm.c view on Meta::CPAN
}
}
/*
*----------------------------------------------------------------------
*
* CreateWrapper --
*
* This function is invoked to create the wrapper window for a toplevel
* window. It is called just before a toplevel is mapped for the first
* time.
*
* Results:
* None.
*
* Side effects:
* The wrapper is created and the toplevel is reparented inside it.
*
*----------------------------------------------------------------------
*/
static void
CreateWrapper(
WmInfo *wmPtr) /* Window manager information for the
* window. */
{
TkWindow *winPtr, *wrapperPtr;
Window parent;
Tcl_HashEntry *hPtr;
int new;
winPtr = wmPtr->winPtr;
if (winPtr->window == None) {
Tk_MakeWindowExist((Tk_Window) winPtr);
}
/*
* The code below is copied from CreateTopLevelWindow, Tk_MakeWindowExist,
* and TkpMakeWindow. The idea is to create an "official" Tk window (so
* that we can get events on it), but to hide the window outside the
* official Tk hierarchy so that it isn't visible to the application. See
* the comments for the other functions if you have questions about this
* code.
*/
wmPtr->wrapperPtr = wrapperPtr = TkAllocWindow(winPtr->dispPtr,
Tk_ScreenNumber((Tk_Window) winPtr), winPtr);
wrapperPtr->dirtyAtts |= CWBorderPixel;
/*
* Tk doesn't normally select for StructureNotifyMask events because the
* events are synthesized internally. However, for wrapper windows we need
* to know when the window manager modifies the window configuration. We
* also need to select on focus change events; these are the only windows
* for which we care about focus changes.
*/
wrapperPtr->flags |= TK_WRAPPER;
wrapperPtr->atts.event_mask |= StructureNotifyMask|FocusChangeMask;
wrapperPtr->atts.override_redirect = winPtr->atts.override_redirect;
if (winPtr->flags & TK_EMBEDDED) {
parent = TkUnixContainerId(winPtr);
} else {
parent = XRootWindow(wrapperPtr->display, wrapperPtr->screenNum);
}
wrapperPtr->window = XCreateWindow(wrapperPtr->display,
parent, wrapperPtr->changes.x, wrapperPtr->changes.y,
(unsigned) wrapperPtr->changes.width,
(unsigned) wrapperPtr->changes.height,
(unsigned) wrapperPtr->changes.border_width, wrapperPtr->depth,
InputOutput, wrapperPtr->visual,
wrapperPtr->dirtyAtts|CWOverrideRedirect, &wrapperPtr->atts);
hPtr = Tcl_CreateHashEntry(&wrapperPtr->dispPtr->winTable,
(char *) wrapperPtr->window, &new);
Tcl_SetHashValue(hPtr, wrapperPtr);
wrapperPtr->mainPtr = winPtr->mainPtr;
wrapperPtr->mainPtr->refCount++;
wrapperPtr->dirtyAtts = 0;
wrapperPtr->dirtyChanges = 0;
wrapperPtr->wmInfoPtr = wmPtr;
/*
* Reparent the toplevel window inside the wrapper.
*/
XReparentWindow(wrapperPtr->display, winPtr->window, wrapperPtr->window,
0, 0);
/*
* Tk must monitor structure events for wrapper windows in order to detect
* changes made by window managers such as resizing, mapping, unmapping,
* etc..
*/
Tk_CreateEventHandler((Tk_Window) wmPtr->wrapperPtr,
WrapperEventMask, WrapperEventProc, (ClientData) wmPtr);
}
/*
*----------------------------------------------------------------------
*
* TkWmFocusToplevel --
*
* This is a utility function invoked by focus-management code. The focus
* code responds to externally generated focus-related events on wrapper
* windows but ignores those events for any other windows. This function
* determines whether a given window is a wrapper window and, if so,
* returns the toplevel window corresponding to the wrapper.
*
* Results:
* If winPtr is a wrapper window, returns a pointer to the corresponding
* toplevel window; otherwise returns NULL.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
TkWindow *
TkWmFocusToplevel(
( run in 0.655 second using v1.01-cache-2.11-cpan-71847e10f99 )