diff --git a/src/E.h b/src/E.h index 7193bede..2ec57506 100644 --- a/src/E.h +++ b/src/E.h @@ -249,6 +249,7 @@ typedef struct Colormap cmap; int scr; int w, h; + Pixmap pmap; /* Compositing buffer */ } VirtRoot; diff --git a/src/Makefile.am b/src/Makefile.am index 5c604fc0..57f89f24 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,6 +1,6 @@ SUBDIRS = -EXTRA_DIST = gnome.c eglx.c eglx.h ecompmgr.c ecompmgr.h snprintf.c +EXTRA_DIST = gnome.c eglx.c eglx.h ecompmgr.c ecompmgr.h magwin.c snprintf.c bin_PROGRAMS = e16 @@ -11,7 +11,7 @@ if HAVE_GLX SRCS_GLX = eglx.c eglx.h endif if HAVE_COMPOSITE -SRCS_ECOMPMGR = ecompmgr.c ecompmgr.h +SRCS_ECOMPMGR = ecompmgr.c ecompmgr.h magwin.c endif if USE_ESNPRINTF SRCS_SNPRINTF = snprintf.c diff --git a/src/ecompmgr.c b/src/ecompmgr.c index bfe35e49..8a276cf0 100644 --- a/src/ecompmgr.c +++ b/src/ecompmgr.c @@ -190,6 +190,7 @@ static struct char active; char use_pixmap; char reorder; + char ghosts; EObj *eo_first; EObj *eo_last; XserverRegion rgn_screen; @@ -438,7 +439,8 @@ EPictureCreateSolid(Bool argb, double a, double r, double g, double b) } static Picture -EPictureCreateBuffer(Window win, int w, int h, int depth, Visual * vis) +EPictureCreateBuffer(Window win, int w, int h, int depth, Visual * vis, + Pixmap * ppmap) { Picture pict; Pixmap pmap; @@ -447,7 +449,10 @@ EPictureCreateBuffer(Window win, int w, int h, int depth, Visual * vis) pmap = XCreatePixmap(disp, win, w, h, depth); pictfmt = XRenderFindVisualFormat(disp, vis); pict = XRenderCreatePicture(disp, pmap, pictfmt, 0, 0); - XFreePixmap(disp, pmap); + if (ppmap) + *ppmap = pmap; + else + XFreePixmap(disp, pmap); return pict; } @@ -490,7 +495,7 @@ ECompMgrMoveResizeFix(EObj * eo, int x, int y, int w, int h) /* Resizing - grab old contents */ pict = EPictureCreateBuffer(EobjGetXwin(eo), wo, ho, WinGetDepth(eo->win), - WinGetVisual(eo->win)); + WinGetVisual(eo->win), NULL); XRenderComposite(disp, PictOpSrc, cw->picture, None, pict, 0, 0, 0, 0, 0, 0, wo, ho); @@ -1831,6 +1836,7 @@ ECompMgrDetermineOrder(EObj * const *lst, int num, EObj ** first, /* Determine overall paint order, top to bottom */ stop = 0; eo_first = eo_prev = NULL; + Mode_compmgr.ghosts = 0; for (i = 0; i < num; i++) { @@ -1905,6 +1911,12 @@ ECompMgrDetermineOrder(EObj * const *lst, int num, EObj ** first, if (cw->picture == None && !eo->noredir) continue; + if (eo->ghost) + { + Mode_compmgr.ghosts = 1; + continue; + } + D3printf ("ECompMgrDetermineOrder hook in %d - %#lx desk=%d shown=%d\n", dsk->num, EobjGetXwin(eo), eo->desk->num, eo->shown); @@ -2100,6 +2112,36 @@ ECompMgrRepaintObj(Picture pbuf, XserverRegion region, EObj * eo, int mode) } } +static void +ECompMgrPaintGhosts(Picture pict, XserverRegion damage) +{ + EObj *eo, *const *lst; + int i, num; + + lst = EobjListStackGet(&num); + for (i = 0; i < num; i++) + { + eo = lst[i]; + if (!eo->shown || !eo->ghost) + continue; + + switch (eo->cmhook->mode) + { + case WINDOW_UNREDIR: + case WINDOW_SOLID: + ECompMgrRepaintObj(pict, Mode_compmgr.rgn_screen, eo, 0); + break; + case WINDOW_TRANS: + case WINDOW_ARGB: + ECompMgrRepaintObj(pict, Mode_compmgr.rgn_screen, eo, 1); + break; + } + + /* Subtract window region from damage region */ + ERegionSubtractOffset(damage, 0, 0, eo->cmhook->shape); + } +} + void ECompMgrRepaint(void) { @@ -2120,7 +2162,7 @@ ECompMgrRepaint(void) if (!rootBuffer) rootBuffer = EPictureCreateBuffer(VRoot.xwin, VRoot.w, VRoot.h, - VRoot.depth, VRoot.vis); + VRoot.depth, VRoot.vis, &VRoot.pmap); pbuf = rootBuffer; if (!dsk) @@ -2154,6 +2196,10 @@ ECompMgrRepaint(void) for (eo = Mode_compmgr.eo_last; eo; eo = ((ECmWinInfo *) (eo->cmhook))->prev) ECompMgrRepaintObj(pbuf, allDamage, eo, 1); + /* Paint any ghost windows (adjusting damage region) */ + if (Mode_compmgr.ghosts) + ECompMgrPaintGhosts(rootPicture, allDamage); + if (pbuf != rootPicture) { XFixesSetPictureClipRegion(dpy, pbuf, 0, 0, allDamage); @@ -2172,30 +2218,31 @@ _ECompMgrIdler(void *data __UNUSED__) if (!allDamage /* || Conf_compmgr.mode == ECM_MODE_AUTO */ ) return; ECompMgrRepaint(); -#if 0 /* FIXME - Was here - Why? */ - XSync(disp, False); -#endif +} + +static void +ECompMgrRootBufferDestroy(void) +{ + /* Root buffer picture and pixmap */ + if (rootBuffer != None) + XRenderFreePicture(disp, rootBuffer); + rootBuffer = None; + if (VRoot.pmap != None) + XFreePixmap(disp, VRoot.pmap); + VRoot.pmap = None; + + /* Screen region */ + if (Mode_compmgr.rgn_screen != None) + ERegionDestroy(Mode_compmgr.rgn_screen); + Mode_compmgr.rgn_screen = None; } static void ECompMgrRootConfigure(void *prm __UNUSED__, XEvent * ev) { - Display *dpy = disp; - D1printf("ECompMgrRootConfigure root\n"); if (ev->xconfigure.window == VRoot.xwin) - { - if (rootBuffer != None) - { - XRenderFreePicture(dpy, rootBuffer); - rootBuffer = None; - } - - if (Mode_compmgr.rgn_screen != None) - ERegionDestroy(Mode_compmgr.rgn_screen); - Mode_compmgr.rgn_screen = None; - } - return; + ECompMgrRootBufferDestroy(); } #if USE_DESK_EXPOSE /* FIXME - Remove? */ @@ -2396,9 +2443,7 @@ ECompMgrStop(void) XRenderFreePicture(disp, rootPicture); rootPicture = None; - if (rootBuffer) - XRenderFreePicture(disp, rootBuffer); - rootBuffer = None; + ECompMgrRootBufferDestroy(); ECompMgrShadowsInit(ECM_SHADOWS_OFF, 0); @@ -2424,10 +2469,6 @@ ECompMgrStop(void) ERegionDestroy(allDamage); allDamage = None; - if (Mode_compmgr.rgn_screen != None) - ERegionDestroy(Mode_compmgr.rgn_screen); - Mode_compmgr.rgn_screen = None; - if (Conf_compmgr.mode == ECM_MODE_ROOT) XCompositeUnredirectSubwindows(disp, VRoot.xwin, CompositeRedirectManual); diff --git a/src/eobj.c b/src/eobj.c index a8ced611..47dd73f8 100644 --- a/src/eobj.c +++ b/src/eobj.c @@ -115,6 +115,8 @@ EobjSetLayer(EObj * eo, int layer) eo->ilayer |= 512; else eo->ilayer &= ~512; + if (eo->ghost) + eo->ilayer |= 1024; if (eo->ilayer != ilayer) EobjRaise(eo); diff --git a/src/eobj.h b/src/eobj.h index 841e2bde..b2e6503d 100644 --- a/src/eobj.h +++ b/src/eobj.h @@ -47,6 +47,7 @@ struct _eobj unsigned noredir:1; /* Do not redirect */ unsigned shadow:1; /* Enable shadows */ unsigned fade:1; /* Enable fading */ + unsigned ghost:1; /* Ghost window */ struct { char *wm_name; diff --git a/src/ewins.h b/src/ewins.h index ba0baeeb..a06ed5cc 100644 --- a/src/ewins.h +++ b/src/ewins.h @@ -285,6 +285,7 @@ struct _ewin #define EWIN_TYPE_MENU 0x02 #define EWIN_TYPE_ICONBOX 0x04 #define EWIN_TYPE_PAGER 0x08 +#define EWIN_TYPE_MISC 0x10 #define EWIN_GRAVITY_NW 0 #define EWIN_GRAVITY_NE 1 diff --git a/src/magwin.c b/src/magwin.c new file mode 100644 index 00000000..4fc868b7 --- /dev/null +++ b/src/magwin.c @@ -0,0 +1,463 @@ +/* + * Copyright (C) 2007 Kim Woelders + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies of the Software, its documentation and marketing & publicity + * materials, and acknowledgment shall be given in the documentation, materials + * and software packages that this Software was used. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#include "E.h" +#include "cursors.h" +#include "ecompmgr.h" +#include "eimage.h" +#include "emodule.h" +#include "eobj.h" +#include "events.h" +#include "ewins.h" +#include "grabs.h" +#include "hints.h" +#include "tclass.h" +#include "timers.h" +#include "util.h" + +#include +#include +#include +#include + +/* Magnifier window */ +typedef struct +{ + EWin *ewin; + EImage *im; + int cx, cy; /* Center */ + int scale; /* Zoom level */ + int sw, sh; /* Scene wxh */ + char mode; + char bpress; + char filter; + char grabbing; +} MagWindow; + +static void MagwinDestroy(MagWindow * mw); + +static MagWindow *MagWin = NULL; + +static void +MagwinDrawText(MagWindow * mw, int x, int y, const char *txt) +{ + TextClass *tc; + int cw, ch; + + tc = TextclassFind("COORDS", 1); + if (!tc) + return; + + TextSize(tc, 0, 0, 0, txt, &cw, &ch, 17); + TextDraw(tc, EwinGetClientWin(mw->ewin), None, 0, 0, 0, + txt, x, y, cw, ch, 17, 0); +} + +static void +MagwinRedraw(MagWindow * mw, int paint) +{ + int ww, wh; + int sx, sy, sw, sh; + double scale; + Drawable draw; + char buf[128]; + int px, py; + int qx, qy; + unsigned int *pd; + + ww = mw->ewin->client.w; + wh = mw->ewin->client.h; + + if (mw->scale < -6) + mw->scale = -6; + else if (mw->scale > 6) + mw->scale = 6; + scale = pow(2., (double)(mw->scale)); + sw = (int)((ww + .999 * scale) / scale); + if (sw > VRoot.w) + scale = (double)ww / (double)VRoot.w; + sh = (int)((wh + .999 * scale) / scale); + if (sh > VRoot.h && scale < (double)wh / (double)VRoot.h) + scale = (double)wh / (double)VRoot.h; + sw = (int)((ww + .999 * scale) / scale); + sh = (int)((wh + .999 * scale) / scale); + sx = mw->cx - sw / 2; + sy = mw->cy - sh / 2; + if (sx < 0) + sx = 0; + else if (sx + sw > VRoot.w) + sx = VRoot.w - sw; + if (sy < 0) + sy = 0; + else if (sy + sh > VRoot.h) + sy = VRoot.h - sh; + mw->sw = sw; + mw->sh = sh; + + if (paint) + { + if (mw->im) + EImageDecache(mw->im); + + draw = (VRoot.pmap != None) ? VRoot.pmap : VRoot.xwin; + mw->im = EImageGrabDrawable(draw, None, sx, sy, sw, sh, 0); + EImageRenderOnDrawable(mw->im, EwinGetClientWin(mw->ewin), + EwinGetClientXwin(mw->ewin), + (mw->filter) ? EIMAGE_ANTI_ALIAS : 0, + 0, 0, (int)(sw * scale + .5), + (int)(sh * scale + .5)); + } + + /* Show magnified area coordinates */ + Esnprintf(buf, sizeof(buf), "%d,%d %dx%d", sx, sy, sw, sh); + MagwinDrawText(mw, 10, 10, buf); + + /* Show info about pixel at cursor (if in magnifier) */ + EQueryPointer(EwinGetClientWin(mw->ewin), &px, &py, NULL, NULL); + if (px < 0 || px >= mw->ewin->client.w || py < 0 || py >= mw->ewin->client.h) + return; + qx = (int)(px / scale); + qy = (int)(py / scale); + if (qx > VRoot.w - 1) + qx = VRoot.w - 1; + if (qy > VRoot.h - 1) + qy = VRoot.h - 1; + if (!mw->im) + return; + pd = (unsigned int *)EImageGetData(mw->im); +#if 0 + Esnprintf(buf, sizeof(buf), "%d,%d: pixel=%#08x (%d,%d)", + sx + qx, sy + qy, pd[qy * sw + qx], px, py); +#else + Esnprintf(buf, sizeof(buf), "%d,%d: pixel=%#08x", + sx + qx, sy + qy, pd[qy * sw + qx]); +#endif + MagwinDrawText(mw, 10, 20, buf); +} + +static void +_MagwinTimeout(int val, void *data) +{ + MagWindow *mw = (MagWindow *) data; + + if (val && mw != MagWin) + return; + + /* Validate ewin */ + if (!EwinFindByPtr(mw->ewin)) + return; + + DoIn("magwin", .050, _MagwinTimeout, 0, data); + + /* FIXME - Check damage */ + MagwinRedraw(mw, 1); +} + +static int +MagwinKeyPress(MagWindow * mw, KeySym key) +{ + switch (key) + { + case XK_q: /* Quit */ + case XK_Escape: + return 1; + case XK_g: /* Toggle grabs */ + if (mw->grabbing) + { + GrabPointerRelease(); + GrabKeyboardRelease(); + mw->grabbing = 0; + } + else + { + GrabPointerSet(EwinGetClientWin(mw->ewin), ECSR_GRAB, 0); + GrabKeyboardSet(EwinGetClientWin(mw->ewin)); + mw->grabbing = 1; + } + break; + case XK_f: /* Toggle filter */ + mw->filter += 1; + if (mw->filter >= 2) + mw->filter = 0; + break; + case XK_i: /* Zoom in */ + case XK_Page_Up: + mw->scale += 1; + break; + case XK_o: /* Zoom out */ + case XK_Page_Down: + mw->scale -= 1; + if (mw->scale < -20) + mw->scale = -20; + break; + case XK_Left: + mw->cx -= 4; + if (mw->cx < mw->sw / 2) + mw->cx = mw->sw / 2; + break; + case XK_Right: + mw->cx += 4; + if (mw->cx > VRoot.w - mw->sw / 2) + mw->cx = VRoot.w - mw->sw / 2; + break; + case XK_Up: + mw->cy -= 4; + if (mw->cy < mw->sh / 2) + mw->cy = mw->sh / 2; + break; + case XK_Down: + mw->cy += 4; + if (mw->cy > VRoot.h - mw->sh / 2) + mw->cy = VRoot.h - mw->sh / 2; + break; + } + + return 0; +} + +static void +MagwinEvent(Win win __UNUSED__, XEvent * ev, void *prm) +{ + MagWindow *mw = (MagWindow *) prm; + KeySym key; + int done = 0; + + switch (ev->type) + { + default: + break; + + case KeyPress: + key = XLookupKeysym(&ev->xkey, 0); + done = MagwinKeyPress(mw, key); + MagwinRedraw(mw, 1); + break; + + case ButtonPress: + switch (ev->xbutton.button) + { + default: + break; + case 1: + MagwinKeyPress(mw, XK_g); + break; + case 3: + MagwinKeyPress(mw, XK_f); + break; + case 4: + MagwinKeyPress(mw, XK_i); + break; + case 5: + MagwinKeyPress(mw, XK_o); + break; + } + mw->bpress = 1; + break; + case ButtonRelease: + mw->bpress = 0; + break; + + case MotionNotify: + if (mw->grabbing) + { + mw->cx = Mode.events.x; + mw->cy = Mode.events.y; + MagwinRedraw(mw, 1); + } + else + { + MagwinRedraw(mw, 0); + } + break; + + case MapNotify: + MagwinKeyPress(mw, XK_g); + _MagwinTimeout(1, mw); + break; + } + + if (done) + EwinHide(mw->ewin); +} + +static void +_MagEwinInit(EWin * ewin) +{ + EoSetSticky(ewin, 1); + EoSetShadow(ewin, 0); +} + +static void +_MagEwinClose(EWin * ewin) +{ + MagwinDestroy((MagWindow *) ewin->data); + ewin->client.win = NULL; + ewin->data = NULL; + MagWin = NULL; +} + +static const EWinOps _MagEwinOps = { + _MagEwinInit, + NULL, + NULL, + _MagEwinClose, +}; + +static MagWindow * +MagwinCreate(const char *title, int width, int height) +{ + MagWindow *mw; + Win win; + int x, y, w, h; + + mw = ECALLOC(MagWindow, 1); + if (!mw) + return NULL; + + win = VRoot.win; + w = width; + h = height; + x = ((win->w - w) / 2); + y = ((win->h - h) / 2); + + win = ECreateClientWindow(VRoot.win, x, y, w, h); + + HintsSetWindowName(win, title); + HintsSetWindowClass(win, "Magnifier", "Enlightenment_Magnifier"); + + mw->ewin = AddInternalToFamily(win, NULL, EWIN_TYPE_MISC, &_MagEwinOps, mw); + if (!mw->ewin) + { + Efree(mw); + return NULL; + } + + mw->ewin->o.ghost = 1; + EoSetLayer(mw->ewin, 10); + EwinMoveToDesktop(mw->ewin, EoGetDesk(mw->ewin)); + EwinMoveResize(mw->ewin, EoGetX(mw->ewin), EoGetY(mw->ewin), w, h); + + mw->ewin->client.event_mask |= + KeyPressMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask | + StructureNotifyMask; + ESelectInput(win, mw->ewin->client.event_mask); + + EventCallbackRegister(win, 0, MagwinEvent, mw); + + EQueryPointer(VRoot.win, &mw->cx, &mw->cy, NULL, NULL); + mw->scale = 1; + + return mw; +} + +static void +MagwinDestroy(MagWindow * mw) +{ + RemoveTimerEvent("magwin"); + EventCallbackUnregister(EwinGetClientWin(mw->ewin), 0, MagwinEvent, mw); + EDestroyWindow(EwinGetClientWin(mw->ewin)); + if (mw->im) + EImageDecache(mw->im); + Efree(mw); +} + +static void +MagwinShow(void) +{ + if (MagWin) + return; + + MagWin = MagwinCreate("Magnifier", VRoot.w / 4, VRoot.h / 4); + if (!MagWin) + { + Eprintf("Failed to create magnifier window\n"); + return; + } + + EwinShow(MagWin->ewin); +} + +static void +MagwinHide(void) +{ + if (!MagWin) + return; + + EwinHide(MagWin->ewin); +} + +/* + * MagWin Module + */ + +static void +MagwinIpc(const char *params, Client * c __UNUSED__) +{ + const char *p; + char cmd[128], prm[4096]; + int len; + + cmd[0] = prm[0] = '\0'; + p = params; + if (p) + { + len = 0; + sscanf(p, "%100s %4000s %n", cmd, prm, &len); + p += len; + } + + if (!p || cmd[0] == '?') + { + IpcPrintf("Magwin: ???\n"); + } + else if (!strcmp(cmd, "show")) + { + MagwinShow(); + } +#if 1 /* FIXME - Remove? */ + else if (!strcmp(cmd, "hide")) + { + MagwinHide(); + } +#endif +} + +static const IpcItem MagwinIpcArray[] = { + { + MagwinIpc, + "magwin", "mag", + "Magnifier functions", + " magwin show\n"} + , +}; +#define N_IPC_FUNCS (sizeof(MagwinIpcArray)/sizeof(IpcItem)) + +/* + * Module descriptor + */ +extern const EModule ModMagwin; +const EModule ModMagwin = { + "magwin", NULL, + NULL, + {N_IPC_FUNCS, MagwinIpcArray}, + {0, NULL} +}; diff --git a/src/mod-misc.c b/src/mod-misc.c index 8d5595a8..17ccd63b 100644 --- a/src/mod-misc.c +++ b/src/mod-misc.c @@ -37,6 +37,7 @@ extern const EModule ModButtons; #if USE_COMPOSITE extern const EModule ModCompMgr; +extern const EModule ModMagwin; #endif extern const EModule ModCursors; extern const EModule ModDesktops; @@ -68,6 +69,7 @@ const EModule *p_modules[] = { &ModButtons, #if USE_COMPOSITE &ModCompMgr, + &ModMagwin, #endif &ModCursors, &ModDesktops,