chiark / gitweb /
Imported Upstream version 1.0.0
[e16] / src / hiwin.c
1 /*
2  * Copyright (C) 2000-2007 Carsten Haitzler, Geoff Harrison and various contributors
3  * Copyright (C) 2004-2008 Kim Woelders
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a copy
6  * of this software and associated documentation files (the "Software"), to
7  * deal in the Software without restriction, including without limitation the
8  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
9  * sell copies of the Software, and to permit persons to whom the Software is
10  * furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in
13  * all copies of the Software, its documentation and marketing & publicity
14  * materials, and acknowledgment shall be given in the documentation, materials
15  * and software packages that this Software was used.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20  * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
21  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23  */
24 #include "E.h"
25 #include "cursors.h"
26 #include "eobj.h"
27 #include "events.h"
28 #include "ewins.h"
29 #include "grabs.h"
30 #include "hiwin.h"
31 #include "iclass.h"
32 #include "xwin.h"
33
34 #define DEBUG_HIWIN 0
35
36 struct _hiwin {
37    EObj                o;
38    EWin               *ewin;
39    int                 zoom;
40    int                 xo, yo, wo, ho;
41    void                (*evcb) (Win win, XEvent * ev, void *data);
42    void               *data;
43    char                animate;
44    GC                  gc;
45    EImage             *im;
46 };
47
48 typedef struct {
49    void                (*init) (Hiwin * phi);
50    void                (*draw) (Hiwin * phi);
51    void                (*fini) (Hiwin * phi, int shown);
52 } HiwinRender;
53
54 static ImageClass  *hiwin_ic = NULL;
55
56 /* TBD: Move elsewhere? */
57 static EImage      *
58 EobjGetImage(EObj * eo, Drawable draw)
59 {
60    EImage             *im;
61    Pixmap              mask;
62
63    mask = EWindowGetShapePixmap(EobjGetWin(eo));
64    im = EImageGrabDrawable(draw, mask, 0, 0, EobjGetW(eo), EobjGetH(eo), 0);
65    if (mask)
66       EFreePixmap(mask);
67
68    return im;
69 }
70
71 static void
72 HiwinRenderImageInit(Hiwin * phi)
73 {
74    EWin               *ewin = phi->ewin;
75    Pixmap              pmap;
76
77    pmap = EoGetPixmap(ewin);
78    if (pmap)
79      {
80         phi->im = EobjGetImage(EoObj(ewin), pmap);
81         /* Skip zoom effect if composite is active */
82         phi->animate = 0;
83      }
84    else if (phi->zoom > 2 && EwinIsOnScreen(ewin))
85      {
86         phi->im = EobjGetImage(EoObj(ewin), EoGetXwin(ewin));
87      }
88    else
89      {
90         phi->im =
91            EImageGrabDrawable(ewin->mini_pmm.pmap, ewin->mini_pmm.mask, 0, 0,
92                               ewin->mini_w, ewin->mini_h, 0);
93      }
94
95    ESetWindowBackgroundPixmap(EoGetWin(phi), None);
96
97    /* Reset shape */
98    EShapeSetMask(EoGetWin(phi), 0, 0, None);
99    EoShapeUpdate(phi, 0);
100 }
101
102 static void
103 HiwinRenderImageDrawX(Hiwin * phi, Drawable draw __UNUSED__)
104 {
105    EImageApplyToWin(phi->im, EoGetWin(phi), EIMAGE_ANTI_ALIAS,
106                     EoGetW(phi), EoGetH(phi));
107    EoShapeUpdate(phi, 0);
108 }
109
110 static void
111 HiwinRenderImageDraw(Hiwin * phi)
112 {
113    HiwinRenderImageDrawX(phi, EoGetXwin(phi));
114 }
115
116 static void
117 HiwinRenderImageFini(Hiwin * phi, int shown)
118 {
119    if (shown)
120       HiwinRenderImageDraw(phi);
121    EImageDecache(phi->im);
122    phi->im = NULL;
123 }
124
125 #if USE_COMPOSITE
126 static void
127 HiwinRenderImageUpdate(Hiwin * phi)
128 {
129    Pixmap              pmap;
130    EWin               *ewin = phi->ewin;
131
132    pmap = EoGetPixmap(ewin);
133    if (pmap == None)
134       return;
135
136    phi->im = EobjGetImage(EoObj(ewin), pmap);
137    HiwinRenderImageDraw(phi);
138    EImageDecache(phi->im);
139    phi->im = NULL;
140 }
141 #endif
142
143 static const HiwinRender HiwinRenderImage = {
144    HiwinRenderImageInit, HiwinRenderImageDraw, HiwinRenderImageFini
145 };
146
147 static void
148 HiwinRenderIclassInit(Hiwin * phi __UNUSED__)
149 {
150 }
151
152 static void
153 HiwinRenderIclassDraw(Hiwin * phi)
154 {
155    ImageclassApply(hiwin_ic, EoGetWin(phi), 0, 0, STATE_NORMAL, ST_PAGER);
156 }
157
158 static void
159 HiwinRenderIclassFini(Hiwin * phi, int shown)
160 {
161    if (shown)
162       HiwinRenderIclassDraw(phi);
163 }
164
165 static const HiwinRender HiwinRenderIclass = {
166    HiwinRenderIclassInit, HiwinRenderIclassDraw, HiwinRenderIclassFini
167 };
168
169 static void
170 HiwinRenderPixmapInit(Hiwin * phi)
171 {
172    phi->gc = EXCreateGC(EoGetXwin(phi), 0, NULL);
173 }
174
175 static void
176 HiwinRenderPixmapDrawX(Hiwin * phi, Drawable draw)
177 {
178    XSetForeground(disp, phi->gc, Dpy.pixel_black);
179    XFillRectangle(disp, draw, phi->gc, 0, 0, EoGetW(phi), EoGetH(phi));
180    XSetForeground(disp, phi->gc, Dpy.pixel_white);
181    XFillRectangle(disp, draw, phi->gc, 1, 1, EoGetW(phi) - 2, EoGetH(phi) - 2);
182 }
183
184 static void
185 HiwinRenderPixmapDraw(Hiwin * phi)
186 {
187    HiwinRenderPixmapDrawX(phi, EoGetXwin(phi));
188    EClearWindow(EoGetWin(phi));
189 }
190
191 static void
192 HiwinRenderPixmapFini(Hiwin * phi, int shown)
193 {
194    Pixmap              pmap;
195
196    if (shown)
197      {
198         pmap = EGetWindowBackgroundPixmap(EoGetWin(phi));
199         HiwinRenderPixmapDrawX(phi, pmap);
200         EClearWindow(EoGetWin(phi));
201      }
202
203    EXFreeGC(phi->gc);
204    phi->gc = None;
205 }
206
207 static const HiwinRender HiwinRenderPixmap = {
208    HiwinRenderPixmapInit, HiwinRenderPixmapDraw, HiwinRenderPixmapFini
209 };
210
211 static void
212 HiwinEvent(Win win, XEvent * ev, void *prm)
213 {
214    Hiwin              *phi = (Hiwin *) prm;
215
216    if (phi->evcb)
217       phi->evcb(win, ev, phi->data);
218 }
219
220 #if USE_COMPOSITE
221 static void
222 HiwinEwinEvent(Win win __UNUSED__, XEvent * ev, void *prm)
223 {
224    Hiwin              *phi = (Hiwin *) prm;
225
226 #if DEBUG_HIWIN
227    Eprintf("HiwinEwinEvent type=%d %s\n", ev->type, EwinGetTitle(phi->ewin));
228 #endif
229
230    switch (ev->type)
231      {
232      case EX_EVENT_DAMAGE_NOTIFY:
233         HiwinRenderImageUpdate(phi);
234         break;
235      }
236 }
237 #endif
238
239 Hiwin              *
240 HiwinCreate(void)
241 {
242    Hiwin              *phi;
243
244    phi = ECALLOC(Hiwin, 1);
245    if (!phi)
246       return NULL;
247
248    EoInit(phi, EOBJ_TYPE_MISC, None, 0, 0, 3, 3, 1, "HiWin");
249    EoSetFade(phi, 1);
250    EoSetFloating(phi, 1);
251    EoSetLayer(phi, 19);
252    EventCallbackRegister(EoGetWin(phi), 0, HiwinEvent, phi);
253    ESelectInput(EoGetWin(phi),
254                 ButtonPressMask | ButtonReleaseMask | PointerMotionMask |
255                 EnterWindowMask | LeaveWindowMask);
256
257    return phi;
258 }
259
260 void
261 HiwinSetGeom(Hiwin * phi, int x, int y, int w, int h)
262 {
263    phi->xo = x;
264    phi->yo = y;
265    phi->wo = w;
266    phi->ho = h;
267 }
268
269 void
270 HiwinInit(Hiwin * phi, EWin * ewin)
271 {
272    if (ewin == phi->ewin)
273       return;
274
275 #if USE_COMPOSITE
276    if (phi->ewin)
277      {
278 #if DEBUG_HIWIN
279         Eprintf("Unregister %s\n", EwinGetTitle(phi->ewin));
280 #endif
281         EventCallbackUnregister(EoGetWin(phi->ewin), 0, HiwinEwinEvent, phi);
282      }
283 #endif
284
285    phi->ewin = ewin;
286
287 #if USE_COMPOSITE
288    if (phi->ewin)
289      {
290 #if DEBUG_HIWIN
291         Eprintf("Register %s\n", EwinGetTitle(phi->ewin));
292 #endif
293         EventCallbackRegister(EoGetWin(phi->ewin), 0, HiwinEwinEvent, phi);
294      }
295 #endif
296
297    if (!hiwin_ic)
298       hiwin_ic = ImageclassFind("PAGER_WIN", 0);
299 }
300
301 void
302 HiwinSetCallback(Hiwin * phi, void (*func) (Win win, XEvent * ev, void *data),
303                  void *data)
304 {
305    phi->evcb = func;
306    phi->data = data;
307 }
308
309 void
310 HiwinGetXY(Hiwin * phi, int *x, int *y)
311 {
312    *x = EoGetX(phi);
313    *y = EoGetY(phi);
314 }
315
316 void
317 HiwinMove(Hiwin * phi, int x, int y)
318 {
319    EoMove(phi, x, y);
320 }
321
322 EWin               *
323 HiwinGetEwin(Hiwin * phi, int check)
324 {
325    EWin               *ewin;
326
327    if (!phi)
328       return NULL;
329    if (!check || !phi->ewin)
330       return phi->ewin;
331
332    ewin = EwinFindByPtr(phi->ewin);
333
334    return ewin;
335 }
336
337 void
338 HiwinHide(Hiwin * phi)
339 {
340    if (!phi)
341       return;
342
343    if (EoIsShown(phi))
344      {
345         GrabPointerRelease();
346         HiwinInit(phi, NULL);
347         EoUnmap(phi);
348      }
349
350    phi->data = NULL;
351    phi->evcb = NULL;
352 }
353
354 void
355 HiwinShow(Hiwin * phi, EWin * ewin, int zoom, int confine)
356 {
357    const HiwinRender  *pz;
358    int                 x, y, w, h, zold;
359    int                 xx, yy, ww, hh, i, i1, i2, step, px, py;
360
361    if (!ewin)
362       ewin = phi->ewin;
363    if (!ewin)
364       return;
365
366    if (ewin->mini_pmm.pmap)
367       pz = &HiwinRenderImage;
368    else if (hiwin_ic)
369       pz = &HiwinRenderIclass;
370    else
371       pz = &HiwinRenderPixmap;
372
373    if (phi->zoom <= 2 && zoom == 2)
374      {
375         phi->zoom = 1;
376
377         x = phi->xo + phi->wo / 2;
378         y = phi->yo + phi->ho / 2;
379         w = zoom * phi->wo;
380         h = zoom * phi->ho;
381
382         step = zoom - phi->zoom;
383      }
384    else if (zoom <= 2)
385      {
386         x = phi->xo + phi->wo / 2;
387         y = phi->yo + phi->ho / 2;
388         w = zoom * phi->wo;
389         h = zoom * phi->ho;
390         step = 0;
391      }
392    else
393      {
394         x = WinGetW(VROOT) / 2;
395         y = WinGetH(VROOT) / 2;
396         w = zoom * EoGetW(phi->ewin) / 4;
397         h = zoom * EoGetH(phi->ewin) / 4;
398         step = 0;
399      }
400
401 #if DEBUG_HIWIN
402    Eprintf("HiwinShow %s zoom=%d->%d step=%d %d,%d %dx%d\n",
403            EoGetName(ewin), phi->zoom, zoom, step, x, y, w, h);
404 #endif
405
406    zold = phi->zoom;
407    phi->zoom = zoom;
408    phi->animate = 1;
409
410    pz->init(phi);
411
412    EoMap(phi, 0);
413
414    if (step && phi->animate)
415      {
416         x = phi->xo;
417         y = phi->yo;
418         w = phi->wo;
419         h = phi->ho;
420
421         if (w > h)
422           {
423              i1 = w * zold;
424              i2 = w * zoom;
425           }
426         else
427           {
428              i1 = h * zold;
429              i2 = h * zoom;
430           }
431
432         for (i = i1; i != i2; i += step)
433           {
434              int                 on_screen;
435
436              if (w > h)
437                {
438                   ww = i;
439                   hh = (ww * h) / w;
440                }
441              else
442                {
443                   hh = i;
444                   ww = (hh * w) / h;
445                }
446              xx = x + ((w - ww) / 2);
447              yy = y + ((h - hh) / 2);
448              EoMoveResize(phi, xx, yy, ww, hh);
449              pz->draw(phi);
450
451              on_screen = EQueryPointer(NULL, &px, &py, NULL, NULL);
452              if (!on_screen ||
453                  (px < x) || (py < y) || (px >= (x + w)) || (py >= (y + h)))
454                {
455                   pz->fini(phi, 0);
456                   HiwinHide(phi);
457                   return;
458                }
459           }
460      }
461    else
462      {
463         EoMoveResize(phi, x - w / 2, y - h / 2, w, h);
464      }
465
466    GrabPointerSet(EoGetWin(phi), ECSR_ACT_MOVE, confine);
467
468    pz->fini(phi, 1);
469 }