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