1 /*
2  * Copyright (C) 2007-2021 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 "config.h"
24 
25 #include <math.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <GL/gl.h>
29 #include <GL/glu.h>
30 #include <GL/glx.h>
31 #include <X11/keysym.h>
32 
33 #include "E.h"
34 #include "animation.h"
35 #include "cursors.h"
36 #include "desktops.h"
37 #include "eimage.h"
38 #include "eglx.h"
39 #include "emodule.h"
40 #include "eobj.h"
41 #include "events.h"
42 #include "ewins.h"
43 #include "grabs.h"
44 #include "util.h"
45 
46 #define ENABLE_DEBUG   1
47 #if ENABLE_DEBUG
48 #define Dprintf(fmt...)  do { if(EDebug(EDBUG_TYPE_GLX))Eprintf(fmt); } while(0)
49 #define D2printf(fmt...) do { if(EDebug(EDBUG_TYPE_GLX)>1)Eprintf(fmt); } while(0)
50 #else
51 #define Dprintf(fmt...)
52 #define D2printf(fmt...)
53 #endif /* ENABLE_DEBUG */
54 
55 static struct {
56    int                 mode;
57 } Conf_glwin;
58 
59 static struct {
60    char                active;
61 } Mode_glwin;
62 
63 typedef struct {
64    EObj               *eo;
65    char                grabbing;
66    EWin               *ewin;
67 } GLWindow;
68 
69 static void         GlwinExit(void);
70 
71 static GLWindow     GLWin;
72 static const char  *image = "pix/about.png";
73 
74 static char         light;	/* Lighting on/off */
75 static GLfloat      rot_x;	/* X rotation */
76 static GLfloat      rot_y;	/* Y rotation */
77 static GLfloat      speed_x;	/* X rotation speed */
78 static GLfloat      speed_y;	/* Y rotation speed */
79 static GLfloat      bg_z;	/* Background z */
80 static unsigned int t0, tn;
81 
82 #define N_TEXTURES 5
83 static unsigned int sel_bg;
84 static unsigned int filter;
85 static ETexture    *texture[N_TEXTURES];
86 static int          sel_ewin;
87 
88 static unsigned int
GetDTime(void)89 GetDTime(void)
90 {
91    return GetTimeMs() - t0;
92 }
93 
94 static void
TexturesLoad(void)95 TexturesLoad(void)
96 {
97    EImage             *im;
98 
99    /* Texture 0 - None */
100    texture[0] = NULL;
101 
102    if (!texture[1])
103      {
104 	im = ThemeImageLoad(image);
105 	if (!im)
106 	  {
107 	     Eprintf("Could not load: %s\n", image);
108 	  }
109 	else
110 	  {
111 	     /* Texture 1 - Filter: None */
112 	     texture[1] = EGlTextureFromImage(im, 0);
113 
114 	     /* Texture 2 - Filter: Linear */
115 	     texture[2] = EGlTextureFromImage(im, 1);
116 
117 	     /* Texture 3 - Mipmap */
118 	     texture[3] = EGlTextureFromImage(im, 2);
119 
120 	     EImageFree(im);
121 	  }
122      }
123 
124    if (!texture[4])
125      {
126 	/* Texture 4 - BG pixmap */
127 	texture[4] =
128 	   EGlTextureFromDrawable(DeskGetBackgroundPixmap(DesksGetCurrent()),
129 				  0);
130      }
131 }
132 
133 static void
SceneResize(unsigned int width,unsigned int height)134 SceneResize(unsigned int width, unsigned int height)
135 {
136    Dprintf("SceneResize\n");
137 
138    glViewport(0, 0, width, height);
139    glMatrixMode(GL_PROJECTION);
140    glLoadIdentity();
141    glOrtho(0, width, 0, height, -1000.f, 1000.f);
142    glMatrixMode(GL_MODELVIEW);
143 }
144 
145 static GLfloat      light_ambient[] = { 0.5f, 0.5f, 0.5f, 1.0f };
146 static GLfloat      light_diffuse[] = { 1.0f, 1.0f, 1.0f, 1.0f };
147 static GLfloat      light_position[] = { 0.0f, 0.0f, 2.0f, 1.0f };
148 
149 static void
SceneInitLight(void)150 SceneInitLight(void)
151 {
152    glLightfv(GL_LIGHT1, GL_AMBIENT, light_ambient);
153    glLightfv(GL_LIGHT1, GL_DIFFUSE, light_diffuse);
154    glLightfv(GL_LIGHT1, GL_POSITION, light_position);
155    glEnable(GL_LIGHT1);
156 }
157 
158 #define L 0.0f
159 #define R 1.0f
160 #define T 0.0f
161 #define B 1.0f
162 
163 static void
DrawBackground(ETexture * et,GLfloat w,GLfloat h)164 DrawBackground(ETexture * et, GLfloat w, GLfloat h)
165 {
166    if (!et)
167       return;
168 
169    glBindTexture(et->target, et->texture);
170 
171    glBegin(GL_QUADS);
172    glNormal3f(0.0f, 0.0f, 1.0f);
173    glTexCoord2f(L, B);
174    glVertex3f(0, 0, bg_z);
175    glTexCoord2f(L, T);
176    glVertex3f(0, h, bg_z);
177    glTexCoord2f(R, T);
178    glVertex3f(w, h, bg_z);
179    glTexCoord2f(R, B);
180    glVertex3f(w, 0, bg_z);
181    glEnd();
182 }
183 
184 static void
DrawQube(ETexture * et,GLfloat x,GLfloat y,GLfloat z,GLfloat w,GLfloat h,GLfloat rx,GLfloat ry)185 DrawQube(ETexture * et, GLfloat x, GLfloat y, GLfloat z, GLfloat w, GLfloat h,
186 	 GLfloat rx, GLfloat ry)
187 {
188    GLfloat             w2, h2, t;
189 
190    if (!et)
191       return;
192 
193    glBindTexture(et->target, et->texture);
194 
195    switch (filter)
196      {
197      default:
198      case 0:
199 	glTexParameteri(et->target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
200 	glTexParameteri(et->target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
201 	break;
202      case 1:
203 	glTexParameteri(et->target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
204 	glTexParameteri(et->target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
205 	break;
206      }
207 
208    glPushMatrix();
209 
210 #if 0
211    x = round(x);
212    y = round(y);
213 #endif
214 
215    glTranslatef(x, y, z);
216 #if 0
217    glScalef(sz, sz, sz);
218 #endif
219    glRotatef(rx, 1.0f, 0.0f, 0.0f);	/* Rotate around X axis */
220    glRotatef(ry, 0.0f, 1.0f, 0.0f);	/* Rotate around Y axis */
221 
222    t = 4.0f;
223    w2 = round(w / 2.f);
224    h2 = round(h / 2.f);
225 
226    glBegin(GL_QUADS);
227 #if 1
228    /* Front */
229    glNormal3f(0.0f, 0.0f, 1.0f);
230    glTexCoord2f(L, B);
231    glVertex3f(-w2, -h2, t);
232    glTexCoord2f(R, B);
233    glVertex3f(w2, -h2, t);
234    glTexCoord2f(R, T);
235    glVertex3f(w2, h2, t);
236    glTexCoord2f(L, T);
237    glVertex3f(-w2, h2, t);
238 #endif
239 #if 1
240    /* Back */
241    glNormal3f(0.0f, 0.0f, 1.0f);
242    glTexCoord2f(L, B);
243    glVertex3f(w2, -h2, -t);
244    glTexCoord2f(R, B);
245    glVertex3f(-w2, -h2, -t);
246    glTexCoord2f(R, T);
247    glVertex3f(-w2, h2, -t);
248    glTexCoord2f(L, T);
249    glVertex3f(w2, h2, -t);
250 #endif
251 #if 1
252    /* Right */
253    glNormal3f(1.0f, 0.0f, 0.0f);
254    glTexCoord2f(L, B);
255    glVertex3f(w2, -h2, t);
256    glTexCoord2f(R, B);
257    glVertex3f(w2, -h2, -t);
258    glTexCoord2f(R, T);
259    glVertex3f(w2, h2, -t);
260    glTexCoord2f(L, T);
261    glVertex3f(w2, h2, t);
262 #endif
263 #if 1
264    /* Left */
265    glNormal3f(-1.0f, 0.0f, 0.0f);
266    glTexCoord2f(L, B);
267    glVertex3f(-w2, -h2, -t);
268    glTexCoord2f(R, B);
269    glVertex3f(-w2, -h2, t);
270    glTexCoord2f(R, T);
271    glVertex3f(-w2, h2, t);
272    glTexCoord2f(L, T);
273    glVertex3f(-w2, h2, -t);
274 #endif
275 #if 1
276    /* Top */
277    glNormal3f(0.0f, 1.0f, 0.0f);
278    glTexCoord2f(L, B);
279    glVertex3f(w2, h2, t);
280    glTexCoord2f(R, B);
281    glVertex3f(w2, h2, -t);
282    glTexCoord2f(R, T);
283    glVertex3f(-w2, h2, -t);
284    glTexCoord2f(L, T);
285    glVertex3f(-w2, h2, t);
286 #endif
287 #if 1
288    /* Bottom */
289    glNormal3f(0.0f, -1.0f, 0.0f);
290    glTexCoord2f(L, B);
291    glVertex3f(w2, -h2, -t);
292    glTexCoord2f(R, B);
293    glVertex3f(w2, -h2, t);
294    glTexCoord2f(R, T);
295    glVertex3f(-w2, -h2, t);
296    glTexCoord2f(L, T);
297    glVertex3f(-w2, -h2, -t);
298 #endif
299    glEnd();
300 
301    glPopMatrix();
302 }
303 
304 static void
SceneDraw2(unsigned int tms,EWin ** ewins,int num)305 SceneDraw2(unsigned int tms, EWin ** ewins, int num)
306 {
307    double              t;
308    int                 i, j, k, nx, ny;
309    GLfloat             x, y, w, h, dx, dy, sz;
310    EObj               *eo;
311 
312    t = 1e-3 * tms;
313 
314    w = EobjGetW(GLWin.eo);
315    h = EobjGetH(GLWin.eo);
316    w = (3 * w) / 4;
317 
318    DrawBackground(texture[sel_bg], w, h);
319 
320    i = (int)sqrt(w * h / (1.0 * num));
321    nx = (int)((w + i - 1) / i);
322    if (nx <= 0)
323       nx = 1;
324    ny = (num + nx - 1) / nx;
325    if (ny <= 0)
326       ny = 1;
327 #if 0
328    Eprintf("wxh=%fx%f num=%d nx,ny=%d,%d\n", w, h, num, nx, ny);
329 #endif
330    w = EobjGetW(GLWin.eo) / nx;
331    h = EobjGetH(GLWin.eo) / ny;
332 
333    k = 0;
334    for (j = 0; j < ny; j++)
335      {
336 	for (i = 0; i < nx; i++)
337 	  {
338 	     if (k >= num)
339 		break;
340 	     x = i * w;
341 	     y = j * h;
342 	     eo = EoObj(ewins[k]);
343 	     dx = 100.0f * exp(-t);
344 	     dx = (fabs(dx) < 1.0) ? 0. : dx * sin(5. * t);
345 	     dy = 100.0f * exp(-t);
346 	     dy = (fabs(dy) < 1.0) ? 0. : dy * cos(5. * t);
347 	     sz = (k == sel_ewin) ? 0.6f : 0.5f;
348 	     DrawQube(EobjGetTexture(eo),
349 		      dx + (0.5f + i) * w, dy + (0.5f + j) * h, 500.0f,
350 		      sz * EobjGetW(eo), sz * EobjGetH(eo), rot_x, rot_y);
351 #if 1
352 	     if (k == sel_ewin)
353 	       {
354 		  glColor3f(1., 0., 0.);
355 		  glRectf(x, y, x + w, y + h);
356 #define X0 x
357 #define Y0 y
358 #define W w
359 #define H h
360 		  glLineWidth(2.);
361 		  glColor3f(0., 1., 0.);
362 		  glBegin(GL_LINE_LOOP);
363 		  glVertex3f(X0, Y0, 0);
364 		  glVertex3f(X0 + W, Y0, 0);
365 		  glVertex3f(X0 + W, Y0 + H, 0);
366 		  glVertex3f(X0, Y0 + H, 0);
367 		  glEnd();
368 		  glColor4f(1., 1., 1., 1.);
369 	       }
370 #endif
371 	     k++;
372 	  }
373      }
374 }
375 
376 static void
SceneDraw1(unsigned int tms,EWin ** ewins,int num)377 SceneDraw1(unsigned int tms, EWin ** ewins, int num)
378 {
379    double              t1, arg;
380    int                 i;
381    GLfloat             w, h, dx, dy, sz;
382    EObj               *eo;
383 
384    w = EobjGetW(GLWin.eo);
385    h = EobjGetH(GLWin.eo);
386 
387    t1 = 2 * M_PI * (-exp(-(20e-3 * (tms - tn))) / num);
388 
389    DrawBackground(texture[sel_bg], w, h);
390 
391    for (i = 0; i < num; i++)
392      {
393 	arg = t1 + M_PI / 2. - (i - sel_ewin) * 2. * M_PI / num;
394 	dx = (.5 + .3 * cos(arg)) * w;
395 	dy = (.5 - .3 * sin(arg)) * h;
396 
397 	eo = EoObj(ewins[i]);
398 	if (i == sel_ewin)
399 	   sz = 0.5 + .01 * cos(10e-3 * (tms - tn));
400 	else
401 	   sz = 0.3;
402 	DrawQube(EobjGetTexture(eo), dx, dy, 500.0,
403 		 sz * EobjGetW(eo), sz * EobjGetH(eo), rot_x, rot_y);
404      }
405 }
406 
407 static EWin       **
GlwinEwins(int * pnum)408 GlwinEwins(int *pnum)
409 {
410    int                 i, j, num;
411    EWin               *const *ewins;
412    EWin              **lst, *ewin;
413 
414    ewins = EwinListGetAll(&num);
415    lst = EMALLOC(EWin *, num);
416 
417    for (i = j = 0; i < num; i++)
418      {
419 	ewin = ewins[i];
420 	if (!EoIsShown(ewin))
421 	   continue;
422 	if (ewin->props.skip_focuslist || ewin->props.skip_ext_task)
423 	   continue;
424 	lst[j++] = ewin;
425      }
426    *pnum = j;
427 
428    return lst;
429 }
430 
431 static void
SceneDraw(void)432 SceneDraw(void)
433 {
434    unsigned int        t;
435    EWin              **ewins;
436    int                 num;
437 
438    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
439    glLoadIdentity();
440 
441    t = GetDTime();
442 
443    ewins = GlwinEwins(&num);
444    if (sel_ewin < 0)
445       sel_ewin = num - 1;
446    else if (sel_ewin >= num)
447       sel_ewin = 0;
448    GLWin.ewin = ewins[sel_ewin];
449 
450    switch (Conf_glwin.mode)
451      {
452      default:
453 	SceneDraw1(t, ewins, num);
454 	break;
455      case 1:
456 	SceneDraw2(t, ewins, num);
457 	break;
458      }
459 
460    glXSwapBuffers(disp, EobjGetXwin(GLWin.eo));
461 
462    Efree(ewins);
463 
464    rot_x += speed_x;
465    rot_y += speed_y;
466 }
467 
468 static int
GlwinRun(EObj * eobj __UNUSED__,int remaining __UNUSED__,void * state __UNUSED__)469 GlwinRun(EObj * eobj __UNUSED__, int remaining __UNUSED__,
470 	 void *state __UNUSED__)
471 {
472    if (!GLWin.eo)
473       return 0;
474    SceneDraw();
475    return 1;
476 }
477 
478 static int
GlwinKeyPress(GLWindow * gw,EX_KeySym keysym)479 GlwinKeyPress(GLWindow * gw, EX_KeySym keysym)
480 {
481    switch (keysym)
482      {
483      case XK_q:
484      case XK_Escape:
485 	return 1;
486 
487      case XK_b:
488 	sel_bg += 1;
489 	if (sel_bg >= N_TEXTURES)
490 	   sel_bg = 0;
491 	break;
492      case XK_f:
493 	filter += 1;
494 	if (filter >= 2)
495 	   filter = 0;
496 	break;
497 
498      case XK_g:		/* Toggle grabs */
499 	if (gw->grabbing)
500 	  {
501 	     GrabPointerRelease();
502 	     GrabKeyboardRelease();
503 	     gw->grabbing = 0;
504 	  }
505 	else
506 	  {
507 	     GrabPointerSet(EobjGetWin(gw->eo), ECSR_GRAB, 0);
508 	     GrabKeyboardSet(EobjGetWin(gw->eo));
509 	     gw->grabbing = 1;
510 	  }
511 	break;
512 
513      case XK_l:
514 	light = !light;
515 	if (!light)
516 	   glDisable(GL_LIGHTING);
517 	else
518 	   glEnable(GL_LIGHTING);
519 	break;
520 
521      case XK_R:		/* Reset */
522 	rot_x = rot_y = 0.0f;
523 	/* FALLTHROUGH */
524 
525      case XK_S:		/* Stop */
526 	bg_z = -2.0f;
527 	speed_x = 0.0f;
528 	speed_y = 0.0f;
529 	break;
530 
531      case XK_Page_Up:
532 	bg_z -= 0.10f;
533 	break;
534      case XK_Page_Down:
535 	bg_z += 0.10f;
536 	break;
537 
538      case XK_Up:
539 	speed_x -= 0.10f;
540 	break;
541      case XK_Down:
542 	speed_x += 0.10f;
543 	break;
544      case XK_Right:
545 	speed_y += 0.10f;
546 	break;
547      case XK_Left:
548 	speed_y -= 0.10f;
549 	break;
550 
551      case XK_m:
552 	Conf_glwin.mode++;
553 	Conf_glwin.mode %= 2;
554 	break;
555 
556      case XK_n:
557      case XK_Tab:
558 	sel_ewin++;
559 	tn = GetDTime();
560 	break;
561      case XK_p:
562 	sel_ewin--;
563 	break;
564 
565      case XK_Return:
566 	if (!gw->ewin)
567 	  {
568 	     Eprintf("No win\n");
569 	     break;
570 	  }
571 	EwinOpActivate(gw->ewin, OPSRC_USER, Conf.warplist.raise_on_select);
572 	return 1;
573      }
574 #define TI(no) ((texture[no]) ? (int)texture[no]->texture : -1)
575    Dprintf("bg=%d(%d) filter=%d l=%d  z=%.2f  spx/y=%.2f/%.2f\n",
576 	   sel_bg, TI(sel_bg), filter, light, bg_z, speed_x, speed_y);
577 
578    return 0;
579 }
580 
581 static void
GlwinEvent(Win win __UNUSED__,XEvent * ev,void * prm)582 GlwinEvent(Win win __UNUSED__, XEvent * ev, void *prm)
583 {
584    GLWindow           *gw = (GLWindow *) prm;
585    EX_KeySym           keysym;
586    int                 done = 0;
587 
588    switch (ev->type)
589      {
590      default:
591 	break;
592      case EX_EVENT_DAMAGE_NOTIFY:
593 	return;
594      }
595 
596    Dprintf("GlwinEvent ev %d\n", ev->type);
597 
598    switch (ev->type)
599      {
600      default:
601 	break;
602      case KeyPress:
603 	keysym = XLookupKeysym(&ev->xkey, ev->xkey.state);
604 	done = GlwinKeyPress(gw, keysym);
605 	break;
606 #if 0
607      case EnterNotify:
608 	GrabKeyboardSet(EobjGetWin(GLWin.eo));
609 	break;
610      case LeaveNotify:
611 	GrabKeyboardRelease();
612 	break;
613 #endif
614      case MapNotify:
615 	GlwinKeyPress(gw, XK_g);
616 	AnimatorAdd(GLWin.eo, ANIM_GLWIN, GlwinRun, -1, 0, 0, NULL);
617 	break;
618 #if 0
619      case ConfigureNotify:
620 	if (ev->xconfigure.width == EobjGetW(GLWin.eo) &&
621 	    ev->xconfigure.height == EobjGetH(GLWin.eo))
622 	   break;
623 	SceneResize(ev->xconfigure.width, ev->xconfigure.height);
624 	break;
625 #endif
626      }
627 
628    if (done)
629       GlwinExit();
630 }
631 
632 static int
GlwinCreate(const char * title __UNUSED__,int width,int height)633 GlwinCreate(const char *title __UNUSED__, int width, int height)
634 {
635    Win                 win;
636    int                 x, y;
637 
638 #if 0
639    win = RROOT;
640 #else
641    win = VROOT;
642 #endif
643    x = ((win->w - width) / 2);
644    y = ((win->h - height) / 2);
645 
646    GLWin.eo = EobjWindowCreate(EOBJ_TYPE_GLX, x, y, width, height, 0, "GLwin");
647    if (!GLWin.eo)
648       return -1;
649    win = EobjGetWin(GLWin.eo);
650    GLWin.eo->fade = GLWin.eo->shadow = 1;
651 
652    EventCallbackRegister(win, GlwinEvent, &GLWin);
653 
654    ESelectInput(win, ExposureMask | KeyPressMask | ButtonPressMask |
655 		StructureNotifyMask);
656 
657    EGlWindowConnect(WinGetXwin(win));
658 
659    GLWin.grabbing = 0;
660    GLWin.ewin = NULL;
661 
662    EobjMap(GLWin.eo, 1);
663 
664    t0 = GetTimeMs();
665    tn = t0;
666 
667    return 0;
668 }
669 
670 static void
GlwinInit(void)671 GlwinInit(void)
672 {
673    bg_z = -2.0f;
674    sel_bg = 0;
675    filter = 0;
676    sel_ewin = 0;
677    light = 0;
678 
679    if (GlwinCreate("GLwin", 640, 480))
680      {
681 	Eprintf("Failed to create window\n");
682 	return;
683      }
684 
685    Mode_glwin.active = 1;
686 
687    TexturesLoad();
688 
689    SceneResize(EobjGetW(GLWin.eo), EobjGetW(GLWin.eo));
690 
691    SceneInitLight();
692 
693    glFlush();
694 }
695 
696 static void
GlwinExit(void)697 GlwinExit(void)
698 {
699    if (!Mode_glwin.active)
700       return;
701 
702    Dprintf("GlTestExit\n");
703 
704    if (GLWin.eo)
705      {
706 	EventCallbackUnregister(EobjGetWin(GLWin.eo), GlwinEvent, &GLWin);
707 	EobjWindowDestroy(GLWin.eo);
708 	GLWin.eo = NULL;
709      }
710 
711 #if 0
712    unsigned int        i;
713 
714    for (i = 0; i < N_TEXTURES; i++)
715      {
716 	EGlTextureDestroy(texture[i]);
717 	texture[i] = NULL;
718      }
719 #endif
720 
721    Mode_glwin.active = 0;
722 }
723 
724 /*
725  * GLwin Module
726  */
727 
728 static void
GlwinSighan(int sig,void * prm __UNUSED__)729 GlwinSighan(int sig, void *prm __UNUSED__)
730 {
731    switch (sig)
732      {
733      case ESIGNAL_START:
734 	break;
735 
736      case ESIGNAL_EXIT:
737 	GlwinExit();
738 	break;
739      }
740 }
741 
742 static void
GlwinIpc(const char * params)743 GlwinIpc(const char *params)
744 {
745    const char         *cmd;
746 
747    cmd = params;
748 
749    if (!cmd)
750      {
751 	GlwinInit();
752      }
753 }
754 
755 static const IpcItem GlwinIpcArray[] = {
756    {
757     GlwinIpc,
758     "glwin", NULL,
759     "Glwin functions",
760     "  glwin\n"}
761    ,
762 };
763 
764 static const CfgItem GlwinCfgItems[] = {
765    CFG_ITEM_INT(Conf_glwin, mode, 0),
766 };
767 
768 /*
769  * Module descriptor
770  */
771 extern const EModule ModGlwin;
772 
773 const EModule       ModGlwin = {
774    "glwin", NULL,
775    GlwinSighan,
776    MOD_ITEMS(GlwinIpcArray),
777    MOD_ITEMS(GlwinCfgItems)
778 };
779