chiark / gitweb /
Imported Upstream version 1.0.0
[e16] / src / magwin.c
1 /*
2  * Copyright (C) 2007-2008 Kim Woelders
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a copy
5  * of this software and associated documentation files (the "Software"), to
6  * deal in the Software without restriction, including without limitation the
7  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
8  * sell copies of the Software, and to permit persons to whom the Software is
9  * furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies of the Software, its documentation and marketing & publicity
13  * materials, and acknowledgment shall be given in the documentation, materials
14  * and software packages that this Software was used.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19  * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
20  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22  */
23 #include "E.h"
24 #include "cursors.h"
25 #include "ecompmgr.h"
26 #include "eimage.h"
27 #include "emodule.h"
28 #include "eobj.h"
29 #include "events.h"
30 #include "ewins.h"
31 #include "grabs.h"
32 #include "hints.h"
33 #include "tclass.h"
34 #include "timers.h"
35 #include "util.h"
36
37 #include <math.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <X11/keysym.h>
41
42 #define USE_TIMER    0
43 #define USE_ANIMATOR 1
44
45 /* Magnifier window */
46 typedef struct {
47    EWin               *ewin;
48    const char         *title;
49 #if USE_TIMER
50    Timer              *timer;
51 #endif
52    int                 cx, cy;  /* Center */
53    int                 scale;   /* Zoom level */
54    int                 sx, sy;  /* Scene x,y */
55    int                 sw, sh;  /* Scene wxh */
56    char                mode;
57    char                bpress;
58    char                filter;
59    char                grabbing;
60    char                step;
61    unsigned int        damage_count;
62    char                update;
63 } MagWindow;
64
65 static void         MagwinDestroy(MagWindow * mw);
66
67 static MagWindow   *MagWin = NULL;
68
69 static void
70 MagwinDrawText(MagWindow * mw, int x, int y, const char *txt)
71 {
72    TextClass          *tc;
73    int                 cw, ch;
74
75    tc = TextclassFind("COORDS", 1);
76    if (!tc)
77       return;
78
79    TextSize(tc, 0, 0, 0, txt, &cw, &ch, 17);
80    TextDraw(tc, EwinGetClientWin(mw->ewin), None, 0, 0, 0,
81             txt, x, y, cw, ch, 17, 0);
82 }
83
84 static unsigned int
85 MagwinGetPixel(Drawable draw, unsigned int x, unsigned int y)
86 {
87    EImage             *im;
88    unsigned int       *pd, pixel;
89
90    im = EImageGrabDrawable(draw, None, x, y, 1, 1, 0);
91    pd = (unsigned int *)EImageGetData(im);
92    pixel = *pd;
93    EImageFree(im);
94
95    return pixel;
96 }
97
98 static void
99 MagwinRedraw(MagWindow * mw, int paint)
100 {
101    int                 ww, wh;
102    int                 sx, sy, sw, sh;
103    double              scale;
104    Drawable            draw;
105    char                buf[128];
106    int                 px, py;
107    int                 qx, qy;
108    int                 out;
109    unsigned int        pixel;
110
111    ww = mw->ewin->client.w;
112    wh = mw->ewin->client.h;
113
114    if (mw->scale < -6)
115       mw->scale = -6;
116    else if (mw->scale > 6)
117       mw->scale = 6;
118    scale = pow(2., (double)(mw->scale));
119    sw = (int)((ww + .999 * scale) / scale);
120    if (sw > WinGetW(VROOT))
121       scale = (double)ww / (double)WinGetW(VROOT);
122    sh = (int)((wh + .999 * scale) / scale);
123    if (sh > WinGetH(VROOT) && scale < (double)wh / (double)WinGetH(VROOT))
124       scale = (double)wh / (double)WinGetH(VROOT);
125    sw = (int)((ww + .999 * scale) / scale);
126    sh = (int)((wh + .999 * scale) / scale);
127    sx = mw->cx - sw / 2;
128    sy = mw->cy - sh / 2;
129    if (sx < 0)
130       sx = 0;
131    else if (sx + sw > WinGetW(VROOT))
132       sx = WinGetW(VROOT) - sw;
133    if (sy < 0)
134       sy = 0;
135    else if (sy + sh > WinGetH(VROOT))
136       sy = WinGetH(VROOT) - sh;
137
138    mw->sx = sx;
139    mw->sy = sy;
140    mw->sw = sw;
141    mw->sh = sh;
142
143    if (paint)
144      {
145         int                 dw, dh;
146
147         dw = (int)(sw * scale + .5);
148         dh = (int)(sh * scale + .5);
149         draw = ECompMgrGetRootBuffer();
150         if (draw == None)
151            draw = WinGetXwin(VROOT);
152         ScaleRect(VROOT, draw, EwinGetClientWin(mw->ewin),
153                   EwinGetClientXwin(mw->ewin), sx, sy, sw, sh,
154                   0, 0, dw, dh, (mw->filter) ? EIMAGE_ANTI_ALIAS : 0);
155      }
156
157    /* Check if pointer is in magnifier window */
158    EQueryPointer(EwinGetClientWin(mw->ewin), &px, &py, NULL, NULL);
159    out = px < 0 || px >= mw->ewin->client.w ||
160       py < 0 || py >= mw->ewin->client.h;
161    /* If inside grab pixel before drawing in window */
162    pixel = (out) ? 0 : MagwinGetPixel(EwinGetClientXwin(mw->ewin), px, py);
163
164    /* Show magnified area coordinates */
165    Esnprintf(buf, sizeof(buf), "%d,%d %dx%d", sx, sy, sw, sh);
166    MagwinDrawText(mw, 10, 10, buf);
167
168    if (out)
169       return;
170
171    /* Show info about pixel at cursor (if in magnifier) */
172    qx = (int)(px / scale);
173    qy = (int)(py / scale);
174    if (qx > WinGetW(VROOT) - 1)
175       qx = WinGetW(VROOT) - 1;
176    if (qy > WinGetH(VROOT) - 1)
177       qy = WinGetH(VROOT) - 1;
178    Esnprintf(buf, sizeof(buf), "%d,%d: pixel=%#08x", sx + qx, sy + qy, pixel);
179    MagwinDrawText(mw, 10, 20, buf);
180 }
181
182 static int
183 _MagwinUpdate(MagWindow * mw)
184 {
185    if (mw != MagWin)
186       return 0;
187
188    /* Validate ewin */
189    if (!EwinFindByPtr(mw->ewin))
190       return 0;
191
192    if (!mw->update && Mode.events.damage_count == mw->damage_count)
193       return 1;
194    mw->damage_count = Mode.events.damage_count;
195
196    /* FIXME - Check damage */
197
198    MagwinRedraw(mw, 1);
199
200    mw->update = 0;
201
202    return 1;
203 }
204
205 #if USE_TIMER
206 static int
207 _MagwinTimeout(int val __UNUSED__, void *data)
208 {
209    MagWindow          *mw = (MagWindow *) data;
210    int                 again;
211
212    again = _MagwinUpdate(mw);
213    if (again)
214       return 1;
215
216    mw->timer = NULL;
217    return 0;
218 }
219 #elif USE_ANIMATOR
220 static int
221 _MagwinAnimator(void *data)
222 {
223    MagWindow          *mw = (MagWindow *) data;
224
225    return _MagwinUpdate(mw);
226 }
227 #endif
228
229 static int
230 MagwinKeyPress(MagWindow * mw, KeySym key)
231 {
232    switch (key)
233      {
234      case XK_q:         /* Quit */
235      case XK_Escape:
236         return 1;
237      case XK_g:         /* Toggle grabs */
238         if (mw->grabbing)
239           {
240              GrabPointerRelease();
241              GrabKeyboardRelease();
242              mw->grabbing = 0;
243           }
244         else
245           {
246              GrabPointerSet(EwinGetClientWin(mw->ewin), ECSR_GRAB, 0);
247              GrabKeyboardSet(EwinGetClientWin(mw->ewin));
248              mw->grabbing = 1;
249           }
250         break;
251      case XK_f:         /* Toggle filter */
252         mw->filter += 1;
253         if (mw->filter >= 2)
254            mw->filter = 0;
255         break;
256      case XK_i:         /* Zoom in */
257      case XK_Page_Up:
258         mw->scale += 1;
259         break;
260      case XK_o:         /* Zoom out */
261      case XK_Page_Down:
262         mw->scale -= 1;
263         if (mw->scale < -20)
264            mw->scale = -20;
265         break;
266
267      case XK_Left:
268         mw->cx -= mw->step;
269         if (mw->cx < mw->sw / 2)
270            mw->cx = mw->sw / 2;
271         break;
272      case XK_Right:
273         mw->cx += mw->step;
274         if (mw->cx > WinGetW(VROOT) - mw->sw / 2)
275            mw->cx = WinGetW(VROOT) - mw->sw / 2;
276         break;
277      case XK_Up:
278         mw->cy -= mw->step;
279         if (mw->cy < mw->sh / 2)
280            mw->cy = mw->sh / 2;
281         break;
282      case XK_Down:
283         mw->cy += mw->step;
284         if (mw->cy > WinGetH(VROOT) - mw->sh / 2)
285            mw->cy = WinGetH(VROOT) - mw->sh / 2;
286         break;
287
288      case XK_r:         /* Switch render mode */
289         Conf.testing.use_render_for_scaling =
290            !Conf.testing.use_render_for_scaling;
291         break;
292
293      case XK_s:         /* x/y move step size */
294         mw->step = (mw->step == 1) ? 4 : 1;
295         break;
296      }
297
298    return 0;
299 }
300
301 static void
302 MagwinEvent(Win win __UNUSED__, XEvent * ev, void *prm)
303 {
304    MagWindow          *mw = (MagWindow *) prm;
305    KeySym              key;
306    int                 done = 0;
307
308    switch (ev->type)
309      {
310      default:
311         break;
312
313      case KeyPress:
314         key = XLookupKeysym(&ev->xkey, 0);
315         done = MagwinKeyPress(mw, key);
316         mw->update = 1;
317         break;
318
319      case ButtonPress:
320         switch (ev->xbutton.button)
321           {
322           default:
323              break;
324           case 1:
325              MagwinKeyPress(mw, XK_g);
326              break;
327           case 3:
328              MagwinKeyPress(mw, XK_f);
329              break;
330           case 4:
331              MagwinKeyPress(mw, XK_i);
332              break;
333           case 5:
334              MagwinKeyPress(mw, XK_o);
335              break;
336           }
337         mw->bpress = 1;
338         mw->update = 1;
339         break;
340      case ButtonRelease:
341         mw->bpress = 0;
342         break;
343
344      case MotionNotify:
345         if (mw->grabbing)
346           {
347              mw->cx = Mode.events.mx;
348              mw->cy = Mode.events.my;
349              mw->update = 1;
350           }
351         else
352           {
353              mw->update = 1;
354           }
355         break;
356
357      case MapNotify:
358         MagwinKeyPress(mw, XK_g);
359 #if USE_TIMER
360         TIMER_ADD(mw->timer, .050, _MagwinTimeout, 0, mw);
361 #elif USE_ANIMATOR
362         AnimatorAdd(_MagwinAnimator, mw);
363 #endif
364         mw->update = 1;
365         break;
366      }
367
368    if (done)
369       EwinHide(mw->ewin);
370 }
371
372 static void
373 _MagEwinInit(EWin * ewin)
374 {
375    MagWindow          *mw = (MagWindow *) ewin->data;
376
377    EwinSetTitle(ewin, mw->title);
378    EwinSetClass(ewin, "Magnifier", "Enlightenment_Magnifier");
379
380    EoSetSticky(ewin, 1);
381    EoSetShadow(ewin, 0);
382 }
383
384 static void
385 _MagEwinClose(EWin * ewin)
386 {
387    MagwinDestroy((MagWindow *) ewin->data);
388    ewin->data = NULL;
389    MagWin = NULL;
390 }
391
392 static const EWinOps _MagEwinOps = {
393    _MagEwinInit,
394    NULL,
395    NULL,
396    _MagEwinClose,
397 };
398
399 static MagWindow   *
400 MagwinCreate(const char *title, int width, int height)
401 {
402    MagWindow          *mw;
403    Win                 win;
404    int                 x, y, w, h;
405
406    mw = ECALLOC(MagWindow, 1);
407    if (!mw)
408       return NULL;
409
410    win = VROOT;
411    w = width;
412    h = height;
413    x = ((win->w - w) / 2);
414    y = ((win->h - h) / 2);
415
416    win = ECreateClientWindow(VROOT, x, y, w, h);
417
418    mw->title = title;
419    mw->ewin = AddInternalToFamily(win, NULL, EWIN_TYPE_MISC, &_MagEwinOps, mw);
420    if (!mw->ewin)
421      {
422         Efree(mw);
423         return NULL;
424      }
425
426    mw->ewin->o.ghost = 1;
427    EoSetLayer(mw->ewin, 10);
428    EwinMoveToDesktop(mw->ewin, EoGetDesk(mw->ewin));
429    EwinMoveResize(mw->ewin, EoGetX(mw->ewin), EoGetY(mw->ewin), w, h);
430
431    mw->ewin->client.event_mask |=
432       KeyPressMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask |
433       StructureNotifyMask;
434    ESelectInput(win, mw->ewin->client.event_mask);
435
436    EventCallbackRegister(win, 0, MagwinEvent, mw);
437
438    EQueryPointer(VROOT, &mw->cx, &mw->cy, NULL, NULL);
439    mw->scale = 1;
440    mw->step = 4;
441
442    return mw;
443 }
444
445 static void
446 MagwinDestroy(MagWindow * mw)
447 {
448 #if USE_TIMER
449    TIMER_DEL(mw->timer);
450 #endif
451    EventCallbackUnregister(EwinGetClientWin(mw->ewin), 0, MagwinEvent, mw);
452    EDestroyWindow(EwinGetClientWin(mw->ewin));
453    Efree(mw);
454 }
455
456 static void
457 MagwinShow(void)
458 {
459    if (MagWin)
460       return;
461
462    MagWin = MagwinCreate(_("Magnifier"),
463                          WinGetW(VROOT) / 4, WinGetH(VROOT) / 4);
464    if (!MagWin)
465      {
466         Eprintf("Failed to create magnifier window\n");
467         return;
468      }
469
470    EwinShow(MagWin->ewin);
471 }
472
473 /*
474  * MagWin Module
475  */
476
477 static void
478 MagwinIpc(const char *params)
479 {
480    const char         *p;
481    char                cmd[128], prm[4096];
482    int                 len;
483
484    cmd[0] = prm[0] = '\0';
485    p = params;
486    if (p)
487      {
488         len = 0;
489         sscanf(p, "%100s %4000s %n", cmd, prm, &len);
490         p += len;
491      }
492
493    if (!p || !strcmp(cmd, "show"))
494      {
495         MagwinShow();
496      }
497 }
498
499 static const IpcItem MagwinIpcArray[] = {
500    {
501     MagwinIpc,
502     "magwin", "mag",
503     "Magnifier functions",
504     "  magwin show\n"}
505    ,
506 };
507 #define N_IPC_FUNCS (sizeof(MagwinIpcArray)/sizeof(IpcItem))
508
509 /*
510  * Module descriptor
511  */
512 extern const EModule ModMagwin;
513 const EModule       ModMagwin = {
514    "magwin", NULL,
515    NULL,
516    {N_IPC_FUNCS, MagwinIpcArray},
517    {0, NULL}
518 };