1 /*
2  * $Source: /cvsroot/cgoban1/cgoban1/wmslib/src/but/i_win.c,v $
3  * $Revision: 1.2 $
4  * $Date: 2000/02/26 23:03:49 $
5  *
6  * wmslib/src/but/i_win.c, part of wmslib (Library functions)
7  * Copyright � 1994-2000 William Shubert.
8  * See "configure.h.in" for more copyright information.
9  */
10 
11 #include <configure.h>
12 
13 #ifdef  X11_DISP
14 
15 #ifdef  STDC_HEADERS
16 #include <stdlib.h>
17 #include <unistd.h>
18 #endif  /* STDC_HEADERS */
19 #include <stdio.h>
20 #include <X11/Xlib.h>
21 #include <X11/Xutil.h>
22 #include <X11/cursorfont.h>
23 #include <X11/Xatom.h>
24 #include <X11/keysym.h>
25 #include <sys/time.h>
26 #ifdef  HAVE_SYS_SELECT_H
27 #include <sys/select.h>
28 #endif
29 #include <wms.h>
30 #include <but/but.h>
31 #include <but/canvas.h>
32 
33 /**********************************************************************
34  * Forward declarations
35  **********************************************************************/
36 static ButWin  *create(void *packet, ButEnv *env, const char *name,
37 		       int w, int h, ButWinFunc *resize);
38 
39 
40 /**********************************************************************
41  * Functions
42  **********************************************************************/
butWin_iCreate(void * packet,ButEnv * env,const char * name,int w,int h,ButWin ** iWin,bool iconic,int iW,int iH,ButWinFunc * unmap,ButWinFunc * map,ButWinFunc * resize,ButWinFunc * iResize,ButWinFunc * destroy)43 ButWin  *butWin_iCreate(void *packet, ButEnv *env,
44 			const char *name, int w, int h,
45 			ButWin **iWin, bool iconic, int iW, int iH,
46 			ButWinFunc *unmap,
47 			ButWinFunc *map,
48 			ButWinFunc *resize,
49 			ButWinFunc *iResize,
50 			ButWinFunc *destroy)  {
51   ButWin  *result;
52 
53   result = create(packet, env, name, w, h, resize);
54   result->unmap = unmap;
55   result->map = map;
56   result->destroy = destroy;
57   result->quit = NULL;
58   if (iWin)  {
59     *iWin = create(packet, env, name, iW, iH, iResize);
60     (*iWin)->isIcon = TRUE;
61     result->iconWin = *iWin;
62     result->iconic = iconic;
63     butWin_activate(*iWin);
64   }
65   return(result);
66 }
67 
68 
create(void * packet,ButEnv * env,const char * name,int w,int h,ButWinFunc * resize)69 static ButWin  *create(void *packet, ButEnv *env, const char *name,
70 		       int w, int h, ButWinFunc *resize)  {
71   ButWin  *win;
72 
73   win = wms_malloc(sizeof(ButWin));
74   MAGIC_SET(win);
75   MAGIC_SET(&win->butsNoDraw);
76   win->parent = NULL;
77   win->parentBut = NULL;
78   win->packet = packet;
79   win->iPacket = NULL;
80   win->win = None;
81   win->physWin = None;
82   win->iconWin = NULL;
83 
84   win->name = name;
85   win->iconic = FALSE;
86   win->isIcon = FALSE;
87   win->x = int_max;
88   win->y = int_max;
89   win->w = win->minW = win->maxW = win->logicalW = w;
90   win->h = win->minH = win->maxH = win->logicalH = h;
91   win->wStep = 1;
92   win->hStep = 1;
93   win->xOff = 0;
94   win->yOff = 0;
95   win->minWRatio = win->minHRatio = win->maxWRatio = win->maxHRatio = 0;
96 
97   win->resized = FALSE;
98   win->resizeNeeded = FALSE;
99   win->redrawReady = TRUE;
100   win->redraws = NULL;
101   win->numRedraws = win->maxRedraws = 0;
102 
103   win->id = 0;
104   win->mapped = FALSE;
105   win->unmap = NULL;
106   win->map = NULL;
107   win->resize = resize;
108   win->destroy = NULL;
109   win->quit = NULL;
110   win->env = env;
111   win->minLayer = 1;
112   win->maxLayer = 0;
113   win->butsNoDraw.buts = NULL;
114   win->butsNoDraw.numButs = 0;
115   win->butsNoDraw.maxButs = 0;
116   win->butsNoDraw.dynamic = TRUE;
117   win->lock = NULL;
118   win->butIn = NULL;
119   win->keyBut = NULL;
120   win->numCols = 0;
121   win->maxCols = 0;
122   win->cols = NULL;
123   return(win);
124 }
125 
126 
butWin_setGeom(ButWin * win,const char * geometry)127 void  butWin_setGeom(ButWin *win, const char *geometry)  {
128   char  xdir = '+', ydir = '+';
129   int  pcount;
130   int  defscr = DefaultScreen(win->env->dpy);
131 
132   assert(MAGIC(win));
133   if (geometry[0] == '=')
134     ++geometry;
135   if ((geometry[0] == '+') || (geometry[0] == '-'))  {
136     pcount = sscanf(geometry, "%c%d%c%d", &xdir, &win->x, &ydir, &win->y);
137     if ((pcount != 4) ||
138 	((xdir != '-') && (xdir != '+')) ||
139 	((ydir != '-') && (ydir != '+')))  {
140       fprintf(stderr, "Error: Cannot understand geometry \"%s\".\n",
141 	      geometry);
142       abort();
143     }
144   } else  {
145     pcount = sscanf(geometry, "%dx%d%c%d%c%d", &win->w, &win->h,
146 		    &xdir, &win->x, &ydir, &win->y);
147     if (((pcount != 2) && (pcount != 6)) ||
148 	((xdir != '-') && (xdir != '+')) ||
149 	((ydir != '-') && (ydir != '+')))  {
150       fprintf(stderr, "Error: Cannot understand geometry \"%s\".\n",
151 	      geometry);
152       abort();
153     }
154   }
155   if (xdir == '-')
156     win->x = DisplayWidth(win->env->dpy, defscr) - win->x - win->w;
157   if (ydir == '-')
158     win->y = DisplayHeight(win->env->dpy, defscr) - win->y - win->h;
159   butWin_checkDims(win);
160 }
161 
162 
butWin_setX(ButWin * win,int x)163 void  butWin_setX(ButWin *win, int x)  {
164   assert(MAGIC(win));
165   win->x = x;
166   butWin_checkDims(win);
167 }
168 
169 
butWin_setY(ButWin * win,int y)170 void  butWin_setY(ButWin *win, int y)  {
171   assert(MAGIC(win));
172   win->y = y;
173   butWin_checkDims(win);
174 }
175 
176 
butWin_setMinW(ButWin * win,int minW)177 void  butWin_setMinW(ButWin *win, int minW)  {
178   assert(MAGIC(win));
179   win->minW = minW;
180   butWin_checkDims(win);
181 }
182 
183 
butWin_setMinH(ButWin * win,int minH)184 void  butWin_setMinH(ButWin *win, int minH)  {
185   assert(MAGIC(win));
186   win->minH = minH;
187   butWin_checkDims(win);
188 }
189 
190 
butWin_setMaxW(ButWin * win,int maxW)191 void  butWin_setMaxW(ButWin *win, int maxW)  {
192   assert(MAGIC(win));
193   if (maxW == 0)
194     maxW = int_max / 2;
195   win->maxW = maxW;
196   butWin_checkDims(win);
197 }
198 
199 
butWin_setMaxH(ButWin * win,int maxH)200 void  butWin_setMaxH(ButWin *win, int maxH)  {
201   assert(MAGIC(win));
202   if (maxH == 0)
203     maxH = int_max / 2;
204   win->maxH = maxH;
205   butWin_checkDims(win);
206 }
207 
208 
butWin_setWHRatio(ButWin * win,int w,int h)209 void  butWin_setWHRatio(ButWin *win, int w, int h)  {
210   assert(MAGIC(win));
211   win->minWRatio = w;
212   win->maxWRatio = w;
213   win->minHRatio = h;
214   win->maxHRatio = h;
215   butWin_checkDims(win);
216 }
217 
218 
butWin_setWHRatios(ButWin * win,int minW,int minH,int maxW,int maxH)219 void  butWin_setWHRatios(ButWin *win,
220 			 int minW, int minH, int maxW, int maxH)  {
221   assert(MAGIC(win));
222   assert(minW / minH <= maxW / maxH);
223   assert(minH / minW >= maxH / maxW);
224   win->minWRatio = minW;
225   win->minHRatio = minH;
226   win->maxWRatio = maxW;
227   win->maxHRatio = maxH;
228   butWin_checkDims(win);
229 }
230 
231 
butWin_setWStep(ButWin * win,int wStep)232 void  butWin_setWStep(ButWin *win, int wStep)  {
233   assert(MAGIC(win));
234   win->wStep = wStep;
235   butWin_checkDims(win);
236 }
237 
238 
butWin_setHStep(ButWin * win,int hStep)239 void  butWin_setHStep(ButWin *win, int hStep)  {
240   assert(MAGIC(win));
241   win->hStep = hStep;
242   butWin_checkDims(win);
243 }
244 
245 
butWin_activate(ButWin * win)246 void  butWin_activate(ButWin *win)  {
247   ButEnv  *env = win->env;
248   Display *dpy = env->dpy;
249   uint  hintmask = USSize;
250   int  defscr = DefaultScreen(dpy);
251   XSizeHints  *sizeHints;
252   XSetWindowAttributes  winattr;
253   XWMHints  wm_hints;
254   XClassHint  class_hints;
255   XTextProperty windowName, iconName;
256   static char  *dumb_argv[] = {NULL};
257   static Atom  protocols[1];
258   /* Stupid X doesn't call their strings const always. */
259   char  *annoyance;
260   char  annoy2[] = "Basicwin";
261 
262   sizeHints = XAllocSizeHints();
263   if (win->x != int_max)  {
264     hintmask |= USPosition;
265     if (win->x + win->w / 2 < 0)
266       win->x = -win->w / 2;
267     if (win->x + win->w / 2 > env->rootW)
268       win->x = env->rootW - win->w/2;
269     if (win->y + win->h / 2 < 0)
270       win->y = -win->h/2;
271     if (win->y + win->h / 2 > env->rootH)
272       win->y = env->rootH - win->h / 2;
273   }
274   winattr.background_pixel = env->colors[BUT_BG];
275   winattr.event_mask = ExposureMask | StructureNotifyMask;
276   winattr.bit_gravity = NorthWestGravity;
277   if (win->isIcon)  {
278     win->win = XCreateWindow(dpy, DefaultRootWindow(dpy), win->x,win->y,
279 			     win->w, win->h, 0, env->depth,
280 			     InputOutput, CopyFromParent,
281 			     CWBackPixel|CWEventMask|CWBitGravity, &winattr);
282     win->physWin = win->win;
283     XSelectInput(dpy, win->win, ExposureMask|StructureNotifyMask);
284   } else  {
285     winattr.event_mask |= PointerMotionMask | ButtonPressMask | KeyPressMask |
286       ButtonReleaseMask | KeyReleaseMask | LeaveWindowMask | FocusChangeMask;
287     win->win = XCreateWindow(dpy, RootWindow(dpy, defscr), win->x,win->y,
288 			     win->w,win->h, 0, env->depth,
289 			     InputOutput, CopyFromParent,
290 			     CWBackPixel|CWEventMask|CWBitGravity, &winattr);
291     win->physWin = win->win;
292     sizeHints->flags = PSize | PMinSize | PMaxSize | hintmask;
293     sizeHints->max_width = win->maxW;
294     sizeHints->max_height = win->maxH;
295     sizeHints->min_width = win->minW;
296     sizeHints->min_height = win->minH;
297     if (win->minWRatio != 0)  {
298       sizeHints->flags |= (PAspect | PBaseSize);
299       sizeHints->min_aspect.x = win->minWRatio;
300       sizeHints->min_aspect.y = win->minHRatio;
301       sizeHints->max_aspect.x = win->maxWRatio;
302       sizeHints->max_aspect.y = win->maxHRatio;
303       sizeHints->base_width = 0;
304       sizeHints->base_height = 0;
305     }
306     if ((win->wStep != 1) || (win->hStep != 1))  {
307       sizeHints->flags |= PResizeInc;
308       sizeHints->width_inc = win->wStep;
309       sizeHints->height_inc = win->hStep;
310     }
311     wm_hints.flags = StateHint | InputHint;
312     if (win->iconWin != None)  {
313       wm_hints.flags |= IconWindowHint;
314       wm_hints.icon_window = win->iconWin->win;
315     }
316     annoyance = wms_malloc(strlen(win->name) + 1);
317     strcpy(annoyance, win->name);
318     if (XStringListToTextProperty(&annoyance, 1, &iconName) == 0)  {
319       fprintf(stderr, "Cannot allocate icon name.\n");
320       abort();
321     }
322     if (XStringListToTextProperty(&annoyance, 1, &windowName) == 0)  {
323       fprintf(stderr, "Cannot allocate window name.\n");
324       abort();
325     }
326     if (win->iconic)
327       wm_hints.initial_state = IconicState;
328     else
329       wm_hints.initial_state = NormalState;
330     wm_hints.input = True;
331 
332     class_hints.res_name = annoyance;
333     class_hints.res_class = annoy2;
334     XSetWMProperties(dpy, win->win, &windowName, &iconName, dumb_argv, 0,
335 		     sizeHints, &wm_hints, &class_hints);
336     protocols[0] = but_wmDeleteWindow;
337     XSetWMProtocols(dpy, win->win, protocols, 1);
338     XMapWindow(dpy, win->win);
339     wms_free(annoyance);
340   }
341   XFree(sizeHints);
342   butWin_addToTable(win);
343 }
344 
345 
butWin_destroy(ButWin * win)346 void  butWin_destroy(ButWin *win)  {
347   if (but_inEvent)  {
348     butWin_dList(win);
349   } else  {
350     while (butWin_delete(win) == BUTOUT_STILLBUTS);
351   }
352 }
353 
354 
butWin_delete(ButWin * win)355 ButOut  butWin_delete(ButWin *win)  {
356   ButEnv  *env = win->env;
357   ButOut  result = 0;
358   int  i, j;
359   ButSet  bset;
360 
361   assert(MAGIC(win));
362   if (win->destroy != NULL)  {
363     /*
364      * This must be done before killing the buttons in case the user wants
365      *   to read some buttons before they go away.
366      */
367     result |= win->destroy(win);
368     win->destroy = NULL;
369   }
370   butWin_findButSetInRegion(win, int_min/2,int_min/2, int_max,int_max, &bset);
371   but_inEvent = TRUE;
372   if ((bset.numButs != 0) || (win->butsNoDraw.numButs != 0))  {
373     for (i = 0;  i < bset.numButs;  ++i)  {
374       but_destroy(bset.buts[i]);
375     }
376     for (i = 0;  i < win->butsNoDraw.numButs;  ++i)  {
377       but_destroy(win->butsNoDraw.buts[i]);
378     }
379     butSet_destroy(&bset);
380     win->butsNoDraw.numButs = 0;
381     return(BUTOUT_STILLBUTS);
382   }
383   if (win->parent)
384     butCan_winDead(win);
385   but_inEvent = FALSE;
386   butSet_destroy(&bset);
387   butSet_destroy(&win->butsNoDraw);
388   /* Remove all timers from the timer list. */
389 
390   /* Clear out the table. */
391   /* Since there can be no buttons left, you can easily wms_free the table. */
392   for (i = 0;  i < win->numCols;  ++i)  {
393     assert(MAGIC(&win->cols[i]));
394     MAGIC_UNSET(&win->cols[i]);
395     for (j = 0;  j < win->cols[i].numRows;  ++j)  {
396       assert(MAGIC(&win->cols[i].rows[j]));
397       MAGIC_UNSET(&win->cols[i].rows[j]);
398       if (win->cols[i].rows[j].buts != NULL)
399 	wms_free(win->cols[i].rows[j].buts);
400     }
401     wms_free(win->cols[i].rows);
402   }
403   wms_free(win->cols);
404   if (env->curwin == win->win)
405     env->curwin = None;
406   if (win->parent)
407     XFreePixmap(env->dpy, win->win);
408   else
409     XDestroyWindow(env->dpy, win->win);
410   if (env->last_mwin == win)
411     env->last_mwin = NULL;
412   butWin_rmFromTable(win);
413   MAGIC_UNSET(&win->butsNoDraw);
414   MAGIC_UNSET(win);
415   wms_free(win);
416   return(result);
417 }
418 
419 
420 /*
421  * Should only be called by a fixed size window.
422  */
butWin_resize(ButWin * win,int newW,int newH)423 void  butWin_resize(ButWin *win, int newW, int newH)  {
424   XSizeHints  *sizeHints;
425 
426   win->minW = win->maxW = newW;
427   win->minH = win->maxH = newH;
428   sizeHints = XAllocSizeHints();
429   sizeHints->flags = PMaxSize | PMinSize | PSize;
430   sizeHints->max_width  = sizeHints->min_width  = sizeHints->width  = newW;
431   sizeHints->max_height = sizeHints->min_height = sizeHints->height = newH;
432   XSetWMNormalHints(win->env->dpy, win->win, sizeHints);
433   XFree(sizeHints);
434   XResizeWindow(win->env->dpy, win->win, newW, newH);
435 }
436 
437 
438 /*
439  * Some window managers (like eXceed/NT) ignore the ratio parts of
440  * a window.  This could break some programs, so here we just ignore
441  * parts of a window if that's the case.  It's ugly, but hey, get
442  * a real window manager.
443  */
butWin_checkDims(ButWin * win)444 void  butWin_checkDims(ButWin *win)  {
445   if (win->w > win->env->rootW)
446     win->w = win->env->rootW;
447   if (win->h > win->env->rootH)
448     win->h = win->env->rootH;
449   if (win->w < win->minW)
450     win->w = win->minW;
451   if (win->w > win->maxW)
452     win->w = win->maxW;
453   if (win->h < win->minH)
454     win->h = win->minH;
455   if (win->h > win->maxH)
456     win->h = win->maxH;
457   win->w -= ((win->w - win->minW) % win->wStep);
458   win->h -= ((win->h - win->minH) % win->hStep);
459   if (win->minWRatio)  {
460     if ((win->w + 1) * win->minHRatio - 1 < win->h * win->minWRatio)
461       win->w = (win->h * win->minWRatio) / win->minHRatio;
462     if ((win->h + 1) * win->maxWRatio - 1 < win->w * win->maxHRatio)
463       win->h = (win->w * win->maxHRatio) / win->maxWRatio;
464   }
465 }
466 
467 
butColor_create(int r,int g,int b,int grey)468 ButColor  butColor_create(int r, int g, int b, int grey)  {
469   ButColor  result;
470 
471   result.red   = (65535L * r + 127) / 255;
472   result.green = (65535L * g + 127) / 255;
473   result.blue  = (65535L * b + 127) / 255;
474   result.greyLevel = grey;
475   return(result);
476 }
477 
478 
butColor_mix(ButColor c1,int r1,ButColor c2,int r2)479 ButColor  butColor_mix(ButColor c1, int r1, ButColor c2, int r2)  {
480   ButColor  res;
481 
482   res.red   = ((c1.red   * r1) + (c2.red   * r2) + (r1 + r2) / 2) / (r1 + r2);
483   res.green = ((c1.green * r1) + (c2.green * r2) + (r1 + r2) / 2) / (r1 + r2);
484   res.blue  = ((c1.blue  * r1) + (c2.blue  * r2) + (r1 + r2) / 2) / (r1 + r2);
485   res.greyLevel = c1.greyLevel;
486   return(res);
487 }
488 
489 
490 #endif  /* X11_DISP */
491