1 /*
2 *
3 Copyright 1989,1998 The Open Group
4
5 Permission to use, copy, modify, distribute, and sell this software and its
6 documentation for any purpose is hereby granted without fee, provided that
7 the above copyright notice appear in all copies and that both that
8 copyright notice and this permission notice appear in supporting
9 documentation.
10
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
21 Except as contained in this notice, the name of The Open Group shall not be
22 used in advertising or otherwise to promote the sale, use or other dealings
23 in this Software without prior written authorization from The Open Group.
24 * */
25
26 /***********************************************************************
27 *
28 * Icon Manager routines
29 *
30 * 09-Mar-89 Tom LaStrange File Created
31 *
32 ***********************************************************************/
33
34 #include <stdio.h>
35 #include "twm.h"
36 #include "util.h"
37 #include "parse.h"
38 #include "screen.h"
39 #include "resize.h"
40 #include "add_window.h"
41 #include "siconify.bm"
42 #include <X11/Xos.h>
43 #include <X11/Xmu/CharSet.h>
44
45 static void InsertInIconManager(IconMgr *ip, WList *tmp, TwmWindow *tmp_win);
46
47 int iconmgr_textx = siconify_width + 11;
48 static WList *Active = NULL;
49 WList *DownIconManager = NULL;
50 int iconifybox_width = siconify_width;
51 int iconifybox_height = siconify_height;
52
53 /**
54 * create all the icon manager windows for this screen.
55 */
56 void
CreateIconManagers(void)57 CreateIconManagers(void)
58 {
59 IconMgr *p;
60 int mask;
61 char str[100];
62 char str1[100];
63 Pixel background;
64 const char *icon_name;
65
66 if (Scr->NoIconManagers)
67 return;
68
69 if (Scr->siconifyPm == None) {
70 Scr->siconifyPm = XCreatePixmapFromBitmapData(dpy, Scr->Root,
71 (char *) siconify_bits,
72 siconify_width,
73 siconify_height, 1, 0, 1);
74 }
75
76 for (p = &Scr->iconmgr; p != NULL; p = p->next) {
77 mask = XParseGeometry(p->geometry, &JunkX, &JunkY,
78 (unsigned int *) &p->width,
79 (unsigned int *) &p->height);
80
81 if (mask & XNegative)
82 JunkX = Scr->MyDisplayWidth - p->width -
83 (2 * Scr->BorderWidth) + JunkX;
84
85 if (mask & YNegative)
86 JunkY = Scr->MyDisplayHeight - p->height -
87 (2 * Scr->BorderWidth) + JunkY;
88
89 background = Scr->IconManagerC.back;
90 GetColorFromList(Scr->IconManagerBL, p->name, (XClassHint *) NULL,
91 &background);
92
93 p->w = XCreateSimpleWindow(dpy, Scr->Root,
94 JunkX, JunkY, (unsigned) p->width,
95 (unsigned) p->height, 1, Scr->Black,
96 background);
97
98 snprintf(str, sizeof(str), "%s Icon Manager", p->name);
99 snprintf(str1, sizeof(str1), "%s Icons", p->name);
100 if (p->icon_name)
101 icon_name = p->icon_name;
102 else
103 icon_name = str1;
104
105 XSetStandardProperties(dpy, p->w, str, icon_name, None, NULL, 0, NULL);
106
107 p->twm_win = AddWindow(p->w, TRUE, p);
108 SetMapStateProp(p->twm_win, WithdrawnState);
109 }
110 for (p = &Scr->iconmgr; p != NULL; p = p->next) {
111 GrabButtons(p->twm_win);
112 GrabKeys(p->twm_win);
113 }
114 }
115
116 /**
117 * allocate a new icon manager
118 *
119 * \param name the name of this icon manager
120 * \param con_name the name of the associated icon
121 * \param geom a geometry string to eventually parse
122 * \param columns the number of columns this icon manager has
123 */
124 IconMgr *
AllocateIconManager(char * name,char * icon_name,char * geom,int columns)125 AllocateIconManager(char *name, char *icon_name, char *geom, int columns)
126 {
127 IconMgr *p;
128
129 #ifdef DEBUG_ICONMGR
130 fprintf(stderr, "AllocateIconManager\n");
131 fprintf(stderr, " name=\"%s\" icon_name=\"%s\", geom=\"%s\", col=%d\n",
132 name, icon_name, geom, columns);
133 #endif
134
135 if (Scr->NoIconManagers)
136 return NULL;
137
138 p = malloc(sizeof(IconMgr));
139 p->name = name;
140 p->icon_name = icon_name;
141 p->geometry = geom;
142 p->columns = columns;
143 p->first = NULL;
144 p->last = NULL;
145 p->active = NULL;
146 p->scr = Scr;
147 p->count = 0;
148 p->x = 0;
149 p->y = 0;
150 p->width = 150;
151 p->height = 10;
152
153 Scr->iconmgr.lasti->next = p;
154 p->prev = Scr->iconmgr.lasti;
155 Scr->iconmgr.lasti = p;
156 p->next = NULL;
157
158 return (p);
159 }
160
161 /**
162 * move the pointer around in an icon manager
163 *
164 * \param dir one of the following:
165 * - F_FORWICONMGR: forward in the window list
166 * - F_BACKICONMGR: backward in the window list
167 * - F_UPICONMGR: up one row
168 * - F_DOWNICONMG: down one row
169 * - F_LEFTICONMGR: left one column
170 * - F_RIGHTICONMGR: right one column
171 */
172 void
MoveIconManager(int dir)173 MoveIconManager(int dir)
174 {
175 IconMgr *ip;
176 WList *tmp = NULL;
177 int cur_row, cur_col, new_row, new_col;
178 int row_inc, col_inc;
179 int got_it;
180
181 if (!Active)
182 return;
183
184 cur_row = Active->row;
185 cur_col = Active->col;
186 ip = Active->iconmgr;
187
188 row_inc = 0;
189 col_inc = 0;
190 got_it = FALSE;
191
192 switch (dir) {
193 case F_FORWICONMGR:
194 if ((tmp = Active->next) == NULL)
195 tmp = ip->first;
196 got_it = TRUE;
197 break;
198
199 case F_BACKICONMGR:
200 if ((tmp = Active->prev) == NULL)
201 tmp = ip->last;
202 got_it = TRUE;
203 break;
204
205 case F_UPICONMGR:
206 row_inc = -1;
207 break;
208
209 case F_DOWNICONMGR:
210 row_inc = 1;
211 break;
212
213 case F_LEFTICONMGR:
214 col_inc = -1;
215 break;
216
217 case F_RIGHTICONMGR:
218 col_inc = 1;
219 break;
220 }
221
222 /* If got_it is FALSE ast this point then we got a left, right,
223 * up, or down, command. We will enter this loop until we find
224 * a window to warp to.
225 */
226 new_row = cur_row;
227 new_col = cur_col;
228
229 while (!got_it) {
230 new_row += row_inc;
231 new_col += col_inc;
232 if (new_row < 0)
233 new_row = ip->cur_rows - 1;
234 if (new_col < 0)
235 new_col = ip->cur_columns - 1;
236 if (new_row >= ip->cur_rows)
237 new_row = 0;
238 if (new_col >= ip->cur_columns)
239 new_col = 0;
240
241 /* Now let's go through the list to see if there is an entry with this
242 * new position
243 */
244 for (tmp = ip->first; tmp != NULL; tmp = tmp->next) {
245 if (tmp->row == new_row && tmp->col == new_col) {
246 got_it = TRUE;
247 break;
248 }
249 }
250 }
251
252 if (!got_it) {
253 fprintf(stderr,
254 "%s: unable to find window (%d, %d) in icon manager\n",
255 ProgramName, new_row, new_col);
256 return;
257 }
258
259 if (tmp == NULL)
260 return;
261
262 /* raise the frame so the icon manager is visible */
263 if (ip->twm_win->mapped) {
264 XRaiseWindow(dpy, ip->twm_win->frame);
265 XWarpPointer(dpy, None, tmp->icon, 0, 0, 0, 0, 5, 5);
266 }
267 else {
268 if (tmp->twm->title_height) {
269 int tbx = Scr->TBInfo.titlex;
270 int x = tmp->twm->highlightx;
271
272 XWarpPointer(dpy, None, tmp->twm->title_w, 0, 0, 0, 0,
273 tbx + (x - tbx) / 2, Scr->TitleHeight / 4);
274 }
275 else {
276 XWarpPointer(dpy, None, tmp->twm->w, 0, 0, 0, 0, 5, 5);
277 }
278 }
279 }
280
281 /**
282 * jump from one icon manager to another, possibly even on another screen
283 * \param dir one of the following:
284 * - F_NEXTICONMGR - go to the next icon manager
285 * - F_PREVICONMGR - go to the previous one
286 */
287
288 void
JumpIconManager(int dir)289 JumpIconManager(int dir)
290 {
291 IconMgr *ip, *tmp_ip = NULL;
292 int got_it = FALSE;
293 ScreenInfo *sp;
294 int screen;
295
296 if (!Active)
297 return;
298
299 #define ITER(i) (dir == F_NEXTICONMGR ? (i)->next : (i)->prev)
300 #define IPOFSP(sp) (dir == F_NEXTICONMGR ? &(sp->iconmgr) : sp->iconmgr.lasti)
301 #define TEST(ip) if ((ip)->count != 0 && (ip)->twm_win->mapped) \
302 { got_it = TRUE; break; }
303
304 ip = Active->iconmgr;
305 for (tmp_ip = ITER(ip); tmp_ip; tmp_ip = ITER(tmp_ip)) {
306 TEST(tmp_ip);
307 }
308
309 if (!got_it) {
310 int origscreen = ip->scr->screen;
311 int inc = (dir == F_NEXTICONMGR ? 1 : -1);
312
313 for (screen = origscreen + inc;; screen += inc) {
314 if (screen >= NumScreens)
315 screen = 0;
316 else if (screen < 0)
317 screen = NumScreens - 1;
318
319 sp = ScreenList[screen];
320 if (sp) {
321 for (tmp_ip = IPOFSP(sp); tmp_ip; tmp_ip = ITER(tmp_ip)) {
322 TEST(tmp_ip);
323 }
324 }
325 if (got_it || screen == origscreen)
326 break;
327 }
328 }
329
330 #undef ITER
331 #undef IPOFSP
332 #undef TEST
333
334 if (!got_it) {
335 Bell(XkbBI_MinorError, 0, None);
336 return;
337 }
338
339 /* raise the frame so it is visible */
340 XRaiseWindow(dpy, tmp_ip->twm_win->frame);
341 if (tmp_ip->active)
342 XWarpPointer(dpy, None, tmp_ip->active->icon, 0, 0, 0, 0, 5, 5);
343 else
344 XWarpPointer(dpy, None, tmp_ip->w, 0, 0, 0, 0, 5, 5);
345 }
346
347 /**
348 * add a window to an icon manager
349 *
350 * \param tmp_win the TwmWindow structure
351 */
352 WList *
AddIconManager(TwmWindow * tmp_win)353 AddIconManager(TwmWindow *tmp_win)
354 {
355 WList *tmp;
356 int h;
357 unsigned long valuemask; /* mask for create windows */
358 XSetWindowAttributes attributes; /* attributes for create windows */
359 IconMgr *ip;
360
361 tmp_win->list = NULL;
362
363 if (tmp_win->iconmgr || tmp_win->transient || Scr->NoIconManagers)
364 return NULL;
365
366 if (LookInList(Scr->IconMgrNoShow, tmp_win->full_name, &tmp_win->class))
367 return NULL;
368 if (Scr->IconManagerDontShow &&
369 !LookInList(Scr->IconMgrShow, tmp_win->full_name, &tmp_win->class))
370 return NULL;
371 if ((ip = (IconMgr *) LookInList(Scr->IconMgrs, tmp_win->full_name,
372 &tmp_win->class)) == NULL)
373 ip = &Scr->iconmgr;
374
375 tmp = malloc(sizeof(WList));
376 tmp->iconmgr = ip;
377 tmp->next = NULL;
378 tmp->active = FALSE;
379 tmp->down = FALSE;
380
381 InsertInIconManager(ip, tmp, tmp_win);
382
383 tmp->twm = tmp_win;
384
385 tmp->fore = Scr->IconManagerC.fore;
386 tmp->back = Scr->IconManagerC.back;
387 tmp->highlight = Scr->IconManagerHighlight;
388
389 GetColorFromList(Scr->IconManagerFL, tmp_win->full_name, &tmp_win->class,
390 &tmp->fore);
391 GetColorFromList(Scr->IconManagerBL, tmp_win->full_name, &tmp_win->class,
392 &tmp->back);
393 GetColorFromList(Scr->IconManagerHighlightL, tmp_win->full_name,
394 &tmp_win->class, &tmp->highlight);
395
396 h = Scr->IconManagerFont.height + 10;
397 if (h < (siconify_height + 4))
398 h = siconify_height + 4;
399
400 ip->height = h * ip->count;
401 tmp->me = ip->count;
402 tmp->x = -1;
403 tmp->y = -1;
404
405 valuemask = (CWBackPixel | CWBorderPixel | CWEventMask | CWCursor);
406 attributes.background_pixel = tmp->back;
407 attributes.border_pixel = tmp->back;
408 attributes.event_mask = (KeyPressMask | ButtonPressMask |
409 ButtonReleaseMask | ExposureMask |
410 EnterWindowMask | LeaveWindowMask);
411 attributes.cursor = Scr->IconMgrCursor;
412 tmp->w = XCreateWindow(dpy, ip->w, 0, 0, (unsigned int) 1,
413 (unsigned int) h, (unsigned int) 0,
414 CopyFromParent, (unsigned int) CopyFromParent,
415 (Visual *) CopyFromParent, valuemask, &attributes);
416
417 valuemask = (CWBackPixel | CWBorderPixel | CWEventMask | CWCursor);
418 attributes.background_pixel = tmp->back;
419 attributes.border_pixel = Scr->Black;
420 attributes.event_mask = (ButtonReleaseMask | ButtonPressMask |
421 ExposureMask);
422 attributes.cursor = Scr->ButtonCursor;
423 tmp->icon = XCreateWindow(dpy, tmp->w, 5, (int) (h - siconify_height) / 2,
424 (unsigned int) siconify_width,
425 (unsigned int) siconify_height,
426 (unsigned int) 0, CopyFromParent,
427 (unsigned int) CopyFromParent,
428 (Visual *) CopyFromParent,
429 valuemask, &attributes);
430
431 ip->count += 1;
432 PackIconManager(ip);
433 XMapWindow(dpy, tmp->w);
434
435 XSaveContext(dpy, tmp->w, IconManagerContext, (XPointer) tmp);
436 XSaveContext(dpy, tmp->w, TwmContext, (XPointer) tmp_win);
437 XSaveContext(dpy, tmp->w, ScreenContext, (XPointer) Scr);
438 XSaveContext(dpy, tmp->icon, TwmContext, (XPointer) tmp_win);
439 XSaveContext(dpy, tmp->icon, ScreenContext, (XPointer) Scr);
440 tmp_win->list = tmp;
441
442 if (!ip->twm_win->icon) {
443 XMapWindow(dpy, ip->w);
444 XMapWindow(dpy, ip->twm_win->frame);
445 }
446
447 if (Active == NULL)
448 Active = tmp;
449
450 return (tmp);
451 }
452
453 /**
454 * put an allocated entry into an icon manager
455 *
456 * \param ip the icon manager pointer
457 * \param tmp the entry to insert
458 */
459 static void
InsertInIconManager(IconMgr * ip,WList * tmp,TwmWindow * tmp_win)460 InsertInIconManager(IconMgr *ip, WList *tmp, TwmWindow *tmp_win)
461 {
462 WList *tmp1;
463 int added;
464 int (*compar) (const char *, const char *)
465 = (Scr->CaseSensitive ? strcmp : XmuCompareISOLatin1);
466
467 added = FALSE;
468 if (ip->first == NULL) {
469 ip->first = tmp;
470 tmp->prev = NULL;
471 ip->last = tmp;
472 added = TRUE;
473 }
474 else if (Scr->SortIconMgr) {
475 for (tmp1 = ip->first; tmp1 != NULL; tmp1 = tmp1->next) {
476 if ((*compar) (tmp_win->icon_name, tmp1->twm->icon_name) < 0) {
477 tmp->next = tmp1;
478 tmp->prev = tmp1->prev;
479 tmp1->prev = tmp;
480 if (tmp->prev == NULL)
481 ip->first = tmp;
482 else
483 tmp->prev->next = tmp;
484 added = TRUE;
485 break;
486 }
487 }
488 }
489
490 if (!added) {
491 ip->last->next = tmp;
492 tmp->prev = ip->last;
493 ip->last = tmp;
494 }
495 }
496
497 static void
RemoveFromIconManager(IconMgr * ip,WList * tmp)498 RemoveFromIconManager(IconMgr *ip, WList *tmp)
499 {
500 if (tmp->prev == NULL)
501 ip->first = tmp->next;
502 else
503 tmp->prev->next = tmp->next;
504
505 if (tmp->next == NULL)
506 ip->last = tmp->prev;
507 else
508 tmp->next->prev = tmp->prev;
509 }
510
511 /**
512 * remove a window from the icon manager
513 * \param tmp_win the TwmWindow structure
514 */
515 void
RemoveIconManager(TwmWindow * tmp_win)516 RemoveIconManager(TwmWindow *tmp_win)
517 {
518 IconMgr *ip;
519 WList *tmp;
520
521 if (tmp_win->list == NULL)
522 return;
523
524 tmp = tmp_win->list;
525 tmp_win->list = NULL;
526 ip = tmp->iconmgr;
527
528 RemoveFromIconManager(ip, tmp);
529
530 XDeleteContext(dpy, tmp->icon, TwmContext);
531 XDeleteContext(dpy, tmp->icon, ScreenContext);
532 XDestroyWindow(dpy, tmp->icon);
533 XDeleteContext(dpy, tmp->w, IconManagerContext);
534 XDeleteContext(dpy, tmp->w, TwmContext);
535 XDeleteContext(dpy, tmp->w, ScreenContext);
536 XDestroyWindow(dpy, tmp->w);
537 ip->count -= 1;
538 free(tmp);
539
540 PackIconManager(ip);
541
542 if (ip->count == 0) {
543 XUnmapWindow(dpy, ip->twm_win->frame);
544 }
545
546 }
547
548 void
ActiveIconManager(WList * active)549 ActiveIconManager(WList *active)
550 {
551 active->active = TRUE;
552 Active = active;
553 Active->iconmgr->active = active;
554 DrawIconManagerBorder(active);
555 }
556
557 void
NotActiveIconManager(WList * active)558 NotActiveIconManager(WList *active)
559 {
560 active->active = FALSE;
561 DrawIconManagerBorder(active);
562 }
563
564 void
DrawIconManagerBorder(WList * tmp)565 DrawIconManagerBorder(WList *tmp)
566 {
567 {
568 XSetForeground(dpy, Scr->NormalGC, tmp->fore);
569 XDrawRectangle(dpy, tmp->w, Scr->NormalGC, 2, 2,
570 (unsigned) (tmp->width - 5),
571 (unsigned) (tmp->height - 5));
572
573 if (tmp->active && Scr->Highlight)
574 XSetForeground(dpy, Scr->NormalGC, tmp->highlight);
575 else
576 XSetForeground(dpy, Scr->NormalGC, tmp->back);
577
578 XDrawRectangle(dpy, tmp->w, Scr->NormalGC, 0, 0,
579 (unsigned) (tmp->width - 1),
580 (unsigned) (tmp->height - 1));
581 XDrawRectangle(dpy, tmp->w, Scr->NormalGC, 1, 1,
582 (unsigned) (tmp->width - 3),
583 (unsigned) (tmp->height - 3));
584 }
585 }
586
587 /**
588 * sort The Dude
589 *
590 * \param ip a pointer to the icon manager struture
591 */
592 void
SortIconManager(IconMgr * ip)593 SortIconManager(IconMgr *ip)
594 {
595 WList *tmp1, *tmp2;
596 int done;
597 int (*compar) (const char *, const char *)
598 = (Scr->CaseSensitive ? strcmp : XmuCompareISOLatin1);
599
600 if (ip == NULL)
601 ip = Active->iconmgr;
602
603 done = FALSE;
604 do {
605 for (tmp1 = ip->first; tmp1 != NULL; tmp1 = tmp1->next) {
606 if ((tmp2 = tmp1->next) == NULL) {
607 done = TRUE;
608 break;
609 }
610 if ((*compar) (tmp1->twm->icon_name, tmp2->twm->icon_name) > 0) {
611 /* take it out and put it back in */
612 RemoveFromIconManager(ip, tmp2);
613 InsertInIconManager(ip, tmp2, tmp2->twm);
614 break;
615 }
616 }
617 }
618 while (!done);
619 PackIconManager(ip);
620 }
621
622 /**
623 * pack the icon manager windows following
624 * an addition or deletion
625 *
626 * \param ip a pointer to the icon manager struture
627 */
628 void
PackIconManager(IconMgr * ip)629 PackIconManager(IconMgr *ip)
630 {
631 int newwidth, i, row, col, maxcol, colinc, rowinc, wheight, wwidth;
632 int new_x, new_y;
633 int savewidth;
634 WList *tmp;
635
636 wheight = Scr->IconManagerFont.height + 10;
637 if (wheight < (siconify_height + 4))
638 wheight = siconify_height + 4;
639
640 wwidth = ip->width / ip->columns;
641
642 rowinc = wheight;
643 colinc = wwidth;
644
645 row = 0;
646 col = ip->columns;
647 maxcol = 0;
648 for (i = 0, tmp = ip->first; tmp != NULL; i++, tmp = tmp->next) {
649 tmp->me = i;
650 if (++col >= ip->columns) {
651 col = 0;
652 row += 1;
653 }
654 if (col > maxcol)
655 maxcol = col;
656
657 new_x = col * colinc;
658 new_y = (row - 1) * rowinc;
659
660 /* if the position or size has not changed, don't touch it */
661 if (tmp->x != new_x || tmp->y != new_y ||
662 tmp->width != wwidth || tmp->height != wheight) {
663 XMoveResizeWindow(dpy, tmp->w,
664 new_x, new_y,
665 (unsigned) wwidth, (unsigned) wheight);
666
667 tmp->row = row - 1;
668 tmp->col = col;
669 tmp->x = new_x;
670 tmp->y = new_y;
671 tmp->width = wwidth;
672 tmp->height = wheight;
673 }
674 }
675 maxcol += 1;
676
677 ip->cur_rows = row;
678 ip->cur_columns = maxcol;
679 ip->height = row * rowinc;
680 if (ip->height == 0)
681 ip->height = rowinc;
682 newwidth = maxcol * colinc;
683 if (newwidth == 0)
684 newwidth = colinc;
685
686 XResizeWindow(dpy, ip->w, (unsigned) newwidth, (unsigned) ip->height);
687
688 savewidth = ip->width;
689 if (ip->twm_win)
690 SetupWindow(ip->twm_win,
691 ip->twm_win->frame_x, ip->twm_win->frame_y,
692 newwidth, ip->height + ip->twm_win->title_height, -1);
693 ip->width = savewidth;
694 }
695