1 /*
2 * wmslib/src/but/i_finder.c, part of wmslib (Library functions)
3 * Copyright (C) 1994 William Shubert.
4 * See "configure.h.in" for more copyright information.
5 */
6
7 #include <configure.h>
8
9 #ifdef X11_DISP
10
11 #ifdef STDC_HEADERS
12 #include <stdlib.h>
13 #include <unistd.h>
14 #endif /* STDC_HEADERS */
15 #include <stdio.h>
16 #include <X11/Xlib.h>
17 #include <X11/Xutil.h>
18 #include <X11/cursorfont.h>
19 #include <X11/Xatom.h>
20 #include <X11/keysym.h>
21 #include <sys/time.h>
22 #ifdef HAVE_SYS_SELECT_H
23 #include <sys/select.h>
24 #endif
25 #include <wms.h>
26 #include <but/but.h>
27
28 static void addButToCol(ButCol *col, But *but, int y1, int y2);
29 static void addButToRow(ButRow *row, But *but);
30 static void copyCol(ButCol *dest, ButCol *src);
31 static void copyRow(ButRow *dest, ButRow *src);
32 static void findButSetInCol(ButCol *col, int x, int y, ButSet *butset);
33 static void butDelFromCol(ButCol *col, But *but);
34 static void butDelFromRow(ButRow *row, But *but);
35 static bool colEq(ButCol *c1, ButCol *c2);
36 static bool rowEq(ButRow *r1, ButRow *r2);
37 static void colDel(ButWin *win, int col_num);
38 static void rowDel(ButCol *col, int row_num);
39 static int markForTable(But *but, void *packet);
40 static int addToTable(But *but, void *packet);
41 static int butcomp(const void *a, const void *b);
42
43 #if 0 /* Useful sometimes for debugging. */
44 void printf_table(but_win_t *win);
45 void printf_env(but_env_t *win);
46 #endif
47
butWin_addToTable(ButWin * win)48 void butWin_addToTable(ButWin *win) {
49 ButEnv *env = win->env;
50 ButWin **new_winlist;
51 int i, j, new_pos;
52
53 assert(MAGIC(win));
54 if (win->win != None) {
55 /*
56 * If win->win is None, then it is a canvas, which does not have to
57 * be entered into the window table yet.
58 */
59 if (env->wlmax == env->wllen) {
60 new_winlist = wms_malloc(sizeof(ButWin *) * (env->wllen + 1) * 2);
61 for (i = 0; i < env->wllen; ++i)
62 new_winlist[i] = env->winlist[i];
63 if (env->winlist != NULL)
64 wms_free(env->winlist);
65 env->winlist = new_winlist;
66 env->wlmax = (env->wllen + 1) * 2;
67 }
68
69 for (i = 0; (i < env->wllen) && (win->win > env->winlist[i]->win); ++i);
70 new_pos = i;
71 for (i = env->wllen; i > new_pos; --i)
72 env->winlist[i] = env->winlist[i-1];
73 env->winlist[new_pos] = win;
74 ++env->wllen;
75 }
76
77 if (win->numCols == 0) {
78 /*
79 * A canvas may call this function every time the pixmap changes, so
80 * we have to make sure that we don't re-allocate all this stuff!
81 */
82 win->numCols = 2;
83 win->maxCols = 2;
84 win->cols = wms_malloc(2 * sizeof(ButCol));
85 win->cols[0].startX = int_min;
86 win->cols[1].startX = int_max;
87 for (i = 0; i < 2; ++i) {
88 MAGIC_SET(&win->cols[i]);
89 win->cols[i].numRows = 2;
90 win->cols[i].maxRows = 2;
91 win->cols[i].rows = wms_malloc(2 * sizeof(ButRow));
92 win->cols[i].rows[0].startY = int_min;
93 win->cols[i].rows[1].startY = int_max;
94 for (j = 0; j < 2; ++j) {
95 MAGIC_SET(&win->cols[i].rows[j]);
96 win->cols[i].rows[j].numButs = 0;
97 win->cols[i].rows[j].maxButs = 0;
98 win->cols[i].rows[j].buts = NULL;
99 }
100 }
101 }
102 #if DEBUG
103 for (i = 1; i < env->wllen; ++i) {
104 assert(env->winlist[i]->win > env->winlist[i - 1]->win);
105 }
106 #endif /* DEBUG */
107 }
108
109
butWin_rmFromTable(ButWin * win)110 void butWin_rmFromTable(ButWin *win) {
111 ButEnv *env = win->env;
112 int i;
113
114 assert(MAGIC(win));
115 assert(MAGIC(env));
116 for (i = 0; (env->winlist[i] != win) && (i < env->wllen); ++i);
117 if (i < env->wllen) {
118 --env->wllen;
119 while (i < env->wllen) {
120 env->winlist[i] = env->winlist[i+1];
121 ++i;
122 }
123 }
124 #if DEBUG
125 for (i = 1; i < env->wllen; ++i) {
126 assert(env->winlist[i]->win > env->winlist[i - 1]->win);
127 }
128 #endif /* DEBUG */
129 }
130
131
but_addToTable(But * but)132 void but_addToTable(But *but) {
133 ButWin *win = but->win;
134 int x1 = but->x, y1 = but->y, x2 = but->x + but->w, y2 = but->y + but->h;
135 int i, src, dest;
136 ButCol *new_cl = win->cols;
137 int new_cll = win->numCols, new_clmax = win->maxCols;
138 int x1done = 0, x2done = 0;
139
140 assert(MAGIC(but));
141 assert(but->flags & BUT_DRAWABLE);
142 butSet_delBut(&win->butsNoDraw, but);
143 for (i = 0; i < new_cll; ++i) {
144 assert(MAGIC(&new_cl[i]));
145 if (new_cl[i].startX == x1)
146 x1done = 1;
147 else if (new_cl[i].startX == x2)
148 x2done = 1;
149 }
150 new_cll += 2 - (x1done + x2done);
151 if (new_cll > win->maxCols) {
152 new_cl = wms_malloc(sizeof(ButCol) * (new_clmax = new_cll * 2));
153 for (i = 0; i < new_clmax; ++i) {
154 MAGIC_SET(&new_cl[i]);
155 new_cl[i].rows = NULL;
156 }
157 }
158 for (src = win->numCols, dest = new_cll; src > 0;) {
159 --src;
160 --dest;
161 assert(MAGIC(&win->cols[src]));
162 if (!x2done && (win->cols[src].startX < x2)) {
163 assert(MAGIC(&new_cl[dest]));
164 copyCol(&new_cl[dest], &win->cols[src]);
165 new_cl[dest--].startX = x2;
166 x2done = 1;
167 }
168 if (!x1done && (win->cols[src].startX < x1)) {
169 assert(MAGIC(&new_cl[dest]));
170 copyCol(&new_cl[dest], &win->cols[src]);
171 new_cl[dest].startX = x1;
172 addButToCol(&new_cl[dest--], but, y1, y2);
173 x1done = 1;
174 }
175 assert(MAGIC(&new_cl[dest]));
176 new_cl[dest] = win->cols[src];
177 if ((new_cl[dest].startX < x2) && (new_cl[dest].startX >= x1))
178 addButToCol(&new_cl[dest], but, y1, y2);
179 }
180 if (win->cols != new_cl) {
181 for (i = 0; i < win->maxCols; ++i)
182 MAGIC_UNSET(&win->cols[i]);
183 wms_free(win->cols);
184 win->cols = new_cl;
185 }
186 win->maxCols = new_clmax;
187 win->numCols = new_cll;
188 }
189
190
addButToCol(ButCol * col,But * but,int y1,int y2)191 static void addButToCol(ButCol *col, But *but, int y1, int y2) {
192 ButRow *new_rl = col->rows;
193 int i, src, dest, new_rll = col->numRows, new_rlmax = col->maxRows;
194 int y1done=0, y2done=0;
195
196 assert(MAGIC(col));
197 assert(MAGIC(but));
198 for (i = 0; i < col->numRows; ++i) {
199 assert(MAGIC(&col->rows[i]));
200 if (col->rows[i].startY == y1)
201 y1done = 1;
202 if (col->rows[i].startY == y2)
203 y2done = 1;
204 }
205 new_rll += 2 - (y1done + y2done);
206 if (new_rll > col->maxRows) {
207 new_rl = wms_malloc(sizeof(ButRow) * (new_rlmax = new_rll * 2));
208 for (i = 0; i < new_rlmax; ++i) {
209 MAGIC_SET(&new_rl[i]);
210 new_rl[i].buts = NULL;
211 }
212 }
213 for (src = col->numRows, dest = new_rll; src > 0;) {
214 --src;
215 --dest;
216 assert(MAGIC(&col->rows[src]));
217 if (!y2done && (col->rows[src].startY < y2)) {
218 assert(MAGIC(&new_rl[dest]));
219 copyRow(&new_rl[dest], &col->rows[src]);
220 new_rl[dest--].startY = y2;
221 y2done = 1;
222 }
223 if (!y1done && (col->rows[src].startY < y1)) {
224 assert(MAGIC(&new_rl[dest]));
225 copyRow(&new_rl[dest], &col->rows[src]);
226 new_rl[dest].startY = y1;
227 addButToRow(&new_rl[dest--], but);
228 y1done = 1;
229 }
230 assert(MAGIC(&new_rl[dest]));
231 new_rl[dest] = col->rows[src];
232 if ((new_rl[dest].startY < y2) && (new_rl[dest].startY >= y1))
233 addButToRow(&new_rl[dest], but);
234 }
235 if (col->rows != new_rl) {
236 if (col->rows != NULL) {
237 wms_free(col->rows);
238 for (i = 0; i < col->maxRows; ++i)
239 MAGIC_UNSET(&col->rows[i]);
240 }
241 col->rows = new_rl;
242 }
243 col->maxRows = new_rlmax;
244 col->numRows = new_rll;
245 }
246
247
addButToRow(ButRow * row,But * but)248 static void addButToRow(ButRow *row, But *but) {
249 int i, new_maxButs = row->maxButs, new_numButs = row->numButs + 1;
250 But **new_bl = row->buts;
251
252 assert(MAGIC(row));
253 assert(MAGIC(but));
254 if (new_numButs >= row->maxButs) {
255 new_bl = wms_malloc(sizeof(But *) * (new_maxButs = new_numButs * 2));
256 for (i = 0; i < row->numButs; ++i)
257 new_bl[i] = row->buts[i];
258 }
259 for (i = row->numButs - 1;
260 (i >= 0) && (but->layer < row->buts[i]->layer); --i) {
261 assert(MAGIC(new_bl[i]));
262 assert(new_bl[i] != but);
263 new_bl[i+1] = new_bl[i];
264 }
265 new_bl[i+1] = but;
266 #if DEBUG
267 for (; i >= 0; --i)
268 assert(new_bl[i] != but);
269 #endif
270 if ((row->buts != NULL) && (row->buts != new_bl))
271 wms_free(row->buts);
272 row->buts = new_bl;
273 row->numButs = new_numButs;
274 row->maxButs = new_maxButs;
275 }
276
277
copyCol(ButCol * dest,ButCol * src)278 static void copyCol(ButCol *dest, ButCol *src) {
279 int i;
280
281 assert(MAGIC(dest));
282 assert(MAGIC(src));
283 *dest = *src;
284 dest->rows = wms_malloc(dest->maxRows * sizeof(ButRow));
285 for (i = 0; i < dest->maxRows; ++i)
286 MAGIC_SET(&dest->rows[i]);
287 for (i = 0; i < dest->numRows; ++i)
288 copyRow(&dest->rows[i], &src->rows[i]);
289 }
290
291
copyRow(ButRow * dest,ButRow * src)292 static void copyRow(ButRow *dest, ButRow *src) {
293 int i;
294
295 assert(MAGIC(dest));
296 assert(MAGIC(src));
297 *dest = *src;
298 dest->buts = wms_malloc(dest->maxButs * sizeof(But *));
299 for (i = 0; i < dest->numButs; ++i)
300 dest->buts[i] = src->buts[i];
301 }
302
303
butWin_findButSet(ButWin * win,int x,int y,ButSet * butset)304 void butWin_findButSet(ButWin *win, int x, int y, ButSet *butset) {
305 unsigned hlen, result = 0, cllen = win->numCols;
306
307 assert(MAGIC(win));
308 butset->dynamic = FALSE;
309 while ((hlen = (cllen >> 1))) {
310 assert(MAGIC(&win->cols[result+hlen]));
311 if (win->cols[result+hlen].startX > x) {
312 cllen = hlen;
313 } else {
314 cllen -= hlen;
315 result += hlen;
316 }
317 }
318 findButSetInCol(&win->cols[result], x, y, butset);
319 }
320
321
findButSetInCol(ButCol * col,int x,int y,ButSet * butset)322 static void findButSetInCol(ButCol *col, int x, int y, ButSet *butset) {
323 unsigned hlen, result = 0, rllen = col->numRows;
324
325 assert(MAGIC(col));
326 while ((hlen = (rllen >> 1))) {
327 assert(MAGIC(&col->rows[result+hlen]));
328 if (col->rows[result+hlen].startY > y) {
329 rllen = hlen;
330 } else {
331 rllen -= hlen;
332 result += hlen;
333 }
334 }
335 butset->numButs = col->rows[result].numButs;
336 butset->buts = col->rows[result].buts;
337 butset->dynamic = FALSE;
338 }
339
340
but_delFromTable(But * but)341 void but_delFromTable(But *but) {
342 ButWin *win = but->win;
343 int i;
344 ButCol *cl = win->cols;
345
346 assert(MAGIC(but));
347 assert(MAGIC(win));
348 for (i = 1; i < win->numCols - 1; ++i) {
349 assert(MAGIC(&cl[i]));
350 if ((cl[i].startX >= but->x) &&
351 (cl[i].startX < but->x + but->w)) {
352 butDelFromCol(&cl[i], but);
353 if (colEq(&cl[i-1], &cl[i])) {
354 colDel(win, i);
355 --i;
356 }
357 if ((i+1 < win->numCols - 1) && colEq(&cl[i], &cl[i+1]))
358 colDel(win, i+1);
359 }
360 }
361 }
362
363
colEq(ButCol * c1,ButCol * c2)364 static bool colEq(ButCol *c1, ButCol *c2) {
365 int i;
366
367 assert(MAGIC(c1));
368 assert(MAGIC(c2));
369 if (c1->numRows != c2->numRows)
370 return(FALSE);
371 for (i = 0; i < c1->numRows; ++i) {
372 if (!rowEq(&c1->rows[i], &c2->rows[i]))
373 return(FALSE);
374 }
375 return(TRUE);
376 }
377
378
rowEq(ButRow * r1,ButRow * r2)379 static bool rowEq(ButRow *r1, ButRow *r2) {
380 int i;
381
382 assert(MAGIC(r1));
383 assert(MAGIC(r2));
384 if (r1->numButs != r2->numButs)
385 return(FALSE);
386 for (i = 0; i < r1->numButs; ++i) {
387 if (r1->buts[i] != r2->buts[i])
388 return(FALSE);
389 }
390 return(TRUE);
391 }
392
393
butDelFromCol(ButCol * col,But * but)394 static void butDelFromCol(ButCol *col, But *but) {
395 int i;
396 ButRow *rl = col->rows;
397
398 assert(MAGIC(col));
399 for (i = 1; i < col->numRows - 1; ++i) {
400 assert(MAGIC(&rl[i]));
401 if ((rl[i].startY >= but->y) &&
402 (rl[i].startY < but->y + but->h)) {
403 butDelFromRow(&rl[i], but);
404 if (rowEq(&rl[i-1], &rl[i])) {
405 rowDel(col, i);
406 --i;
407 }
408 if ((i+1 < col->numRows - 1) && rowEq(&rl[i], &rl[i+1]))
409 rowDel(col, i+1);
410 }
411 }
412 }
413
414
butDelFromRow(ButRow * row,But * but)415 static void butDelFromRow(ButRow *row, But *but) {
416 int dest, src;
417
418 assert(MAGIC(row));
419 for (dest = 0, src = 0; src < row->numButs; ++src) {
420 assert(MAGIC(row->buts[src]));
421 row->buts[dest] = row->buts[src];
422 if (row->buts[dest] != but) {
423 ++dest;
424 } else {
425 assert(src == dest);
426 }
427 }
428 assert(src == dest + 1);
429 --row->numButs;
430 assert(dest == row->numButs);
431 }
432
433
colDel(ButWin * win,int col_num)434 static void colDel(ButWin *win, int col_num) {
435 int i;
436
437 assert(MAGIC(win));
438 assert(MAGIC(&win->cols[col_num]));
439 for (i = 0; i < win->cols[col_num].numRows; ++i) {
440 assert(MAGIC(&win->cols[col_num].rows[i]));
441 if (win->cols[col_num].rows[i].buts != NULL)
442 wms_free(win->cols[col_num].rows[i].buts);
443 }
444 wms_free(win->cols[col_num].rows);
445 --win->numCols;
446 for (i = col_num; i < win->numCols; ++i)
447 win->cols[i] = win->cols[i+1];
448 }
449
450
rowDel(ButCol * col,int row_num)451 static void rowDel(ButCol *col, int row_num) {
452 int i;
453
454 assert(MAGIC(col));
455 assert(MAGIC(&col->rows[row_num]));
456 if (col->rows[row_num].buts != NULL)
457 wms_free(col->rows[row_num].buts);
458 --col->numRows;
459 for (i = row_num; i < col->numRows; ++i)
460 col->rows[i] = col->rows[i+1];
461 }
462
463
butWin_findButSetInRegion(ButWin * win,int x,int y,int w,int h,ButSet * butset)464 void butWin_findButSetInRegion(ButWin *win, int x, int y, int w, int h,
465 ButSet *butset) {
466 assert(MAGIC(win));
467 butset->numButs = 0;
468 butset->dynamic = TRUE;
469 butWin_findButsInRegion(win, x,y, w,h, markForTable, butset);
470 if (butset->numButs > 0) {
471 butset->buts = wms_malloc(butset->numButs * sizeof(But *));
472 butset->maxButs = butset->numButs;
473 butset->numButs = 0;
474 butWin_findButsInRegion(win, x,y, w,h, addToTable, butset);
475 qsort(butset->buts, butset->numButs, sizeof(But *), butcomp);
476 } else {
477 butset->dynamic = FALSE;
478 butset->buts = NULL;
479 }
480 }
481
482
markForTable(But * but,void * packet)483 static int markForTable(But *but, void *packet) {
484 ButSet *butset = packet;
485
486 if (but == NULL) {
487 return(0);
488 }
489 assert(MAGIC(but));
490 if ((but->flags & (BUT_TABLED|BUT_DEAD|BUT_DRAWABLE)) == BUT_DRAWABLE) {
491 ++butset->numButs;
492 but->flags |= BUT_TABLED;
493 }
494 return(0);
495 }
496
497
addToTable(But * but,void * packet)498 static int addToTable(But *but, void *packet) {
499 ButSet *butset = packet;
500
501 assert(MAGIC(but));
502 if (but->flags & BUT_TABLED) {
503 butset->buts[butset->numButs++] = but;
504 assert(butset->numButs <= butset->maxButs);
505 but->flags &= ~BUT_TABLED;
506 }
507 return(0);
508 }
509
510
butcomp(const void * a,const void * b)511 static int butcomp(const void *a, const void *b) {
512 const But *but_a = *(But **)a;
513 const But *but_b = *(But **)b;
514
515 assert(MAGIC(but_a));
516 assert(MAGIC(but_b));
517 if (but_a->layer != but_b->layer)
518 return(but_a->layer - but_b->layer);
519 else if (but_a > but_b)
520 return(-1);
521 else
522 return(1);
523 }
524
525
butEnv_findWin(ButEnv * env,Window win)526 ButWin *butEnv_findWin(ButEnv *env, Window win) {
527 int wmin = 0, wmax = env->wllen, wnum;
528
529 #if DEBUG
530 for (wnum = 1; wnum < env->wllen; ++wnum) {
531 assert(env->winlist[wnum]->win > env->winlist[wnum - 1]->win);
532 }
533 #endif /* DEBUG */
534 while (wmin < wmax) {
535 wnum = (wmax + wmin) >> 1;
536 assert(MAGIC(env->winlist[wnum]));
537 if (env->winlist[wnum]->win == win) {
538 return(env->winlist[wnum]);
539 }
540 if (env->winlist[wnum]->win > win) {
541 wmax = wnum;
542 } else {
543 wmin = wnum + 1;
544 }
545 }
546 return(NULL);
547 }
548
549
butWin_findButsInRegion(ButWin * win,int x,int y,int w,int h,bool (* action)(But * but,void * packet),void * packet)550 But *butWin_findButsInRegion(ButWin *win, int x,int y, int w,int h,
551 bool (*action)(But *but, void *packet),
552 void *packet) {
553 int r, c, b;
554 ButCol *col;
555 ButRow *row;
556 But *but;
557
558 assert(MAGIC(win));
559 for (c = 1; c < win->numCols - 1; ++c) {
560 col = &win->cols[c];
561 assert(MAGIC(col));
562 if ((col->startX < x+w) && (win->cols[c+1].startX > x)) {
563 for (r = 1; r < col->numRows - 1; ++r) {
564 row = &col->rows[r];
565 assert(MAGIC(row));
566 if ((row->startY < y+h) && (col->rows[r+1].startY > y)) {
567 for (b = 0; b < row->numButs; ++b) {
568 but = row->buts[b];
569 assert(MAGIC(but));
570 if (action(but, packet))
571 return(but);
572 }
573 }
574 }
575 }
576 }
577 return(NULL);
578 }
579
580
581 #if 0 /* Sometimes useful for debugging. */
582 void printf_env(but_env_t *env) {
583 int i;
584
585 printf("Env has %d (max %d) windows:\n", env->wllen, env->wlmax);
586 for (i = 0; i < env->wllen; ++i)
587 printf(" 0x%x (x win %d)\n", (int)env->winlist[i],
588 (int)(env->winlist[i]->win));
589 }
590
591
592 void printf_table(but_win_t *win) {
593 int i, j, k;
594
595 for (i = 0; i < win->numCols - 1; ++i) {
596 printf("Col %d of %d: %d..%d\n", i+1, win->numCols - 1,
597 win->cols[i].startX, win->cols[i+1].startX - 1);
598 for (j = 0; j < win->cols[i].numRows - 1; ++j) {
599 printf(" Row %d of %d: %d..%d\n", j+1, win->cols[i].numRows - 1,
600 win->cols[i].rows[j].startY, win->cols[i].rows[j+1].startY - 1);
601 if (win->cols[i].rows[j].numButs == 0)
602 printf(" No buttons.\n");
603 else {
604 for (k = 0; k < win->cols[i].rows[j].numButs; ++k)
605 printf(" But 0x%x\n", (int)win->cols[i].rows[j].buts[k]);
606 }
607 }
608 }
609 printf("---\n");
610 }
611 #endif
612
613
butSet_addBut(ButSet * butset,But * but)614 void butSet_addBut(ButSet *butset, But *but) {
615 int i, new_maxButs;
616 But **newbuts;
617
618 assert(MAGIC(butset));
619 assert(butset->dynamic);
620 for (i = 0; i < butset->numButs; ++i) {
621 if (butset->buts[i] == but)
622 return;
623 }
624 if (butset->numButs == butset->maxButs) {
625 new_maxButs = (butset->maxButs + 1) * 2;
626 newbuts = wms_malloc(new_maxButs * sizeof(But *));
627 if (butset->buts != NULL) {
628 memcpy(newbuts, butset->buts, butset->maxButs * sizeof(But *));
629 wms_free(butset->buts);
630 }
631 butset->buts = newbuts;
632 butset->maxButs = new_maxButs;
633 }
634 butset->buts[butset->numButs++] = but;
635 }
636
637
butSet_delBut(ButSet * butset,But * but)638 void butSet_delBut(ButSet *butset, But *but) {
639 int i;
640
641 assert(MAGIC(butset));
642 for (i = 0; i < butset->numButs; ++i) {
643 if (butset->buts[i] == but) {
644 butset->buts[i] = butset->buts[--butset->numButs];
645 return;
646 }
647 }
648 }
649
650
651 #endif
652