464 lines
10 KiB
C
464 lines
10 KiB
C
/*
|
|
* 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 <math.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <X11/keysym.h>
|
|
|
|
/* 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}
|
|
};
|