Merge branch 'master' of ssh://git.code.sf.net/p/cdesktopenv/code
[oweals/cde.git] / cde / programs / dtstyle / Backdrop.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these librararies and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /* $TOG: Backdrop.c /main/7 1998/11/25 14:48:36 samborn $ */
24 /************************************<+>*************************************
25  ****************************************************************************
26  **
27  **   File:        Backdrop.c
28  **
29  **   Project:     DT 3.0 
30  **
31  **   Description: Controls the Dtstyle Backdrop dialog
32  **
33  **
34  **  (c) Copyright Hewlett-Packard Company, 1990, 1993.  
35  **
36  **
37  **
38  ****************************************************************************
39  ************************************<+>*************************************/
40
41 /*+++++++++++++++++++++++++++++++++++++++*/
42 /* include files                         */
43 /*+++++++++++++++++++++++++++++++++++++++*/
44 #include <stdio.h>
45 #include <string.h>
46 #include <stdlib.h>
47 #include <sys/types.h>
48
49 #if defined(_AIX) || defined(__apollo)
50 #include <sys/dir.h>
51 #else
52 #include <dirent.h>             /* opendir(), directory(3C) */
53 #endif /* _AIX */
54
55 #ifdef __apollo
56 #include <X11/apollosys.h>      /* needed for S_ISDIR macro */
57 #endif
58
59
60 #include <locale.h>
61 #include <X11/Xlib.h>
62 #include <Xm/MwmUtil.h>
63
64 #include <Xm/Xm.h>
65 #include <Xm/XmP.h>
66 #include <Xm/DrawnB.h>
67 #include <Xm/Form.h>
68 #include <Xm/List.h>
69 #include <Xm/VendorSEP.h>
70 #include <Xm/AtomMgr.h>
71
72 #include <Dt/DialogBox.h>
73
74 #include <Dt/Message.h>
75 #include <Dt/SessionM.h>
76 #include <Dt/HourGlass.h>
77 #include <Dt/Wsm.h>
78 #include <Dt/UserMsg.h>
79
80 #include "Help.h"
81 #include "Main.h"
82 #include "SaveRestore.h"
83
84 /*+++++++++++++++++++++++++++++++++++++++*/
85 /* include extern functions              */
86 /*+++++++++++++++++++++++++++++++++++++++*/
87 #include "Backdrop.h"
88
89
90 /*+++++++++++++++++++++++++++++++++++++++*/
91 /* Local #defines                        */
92 /*+++++++++++++++++++++++++++++++++++++++*/
93 #define MAX_STR_LEN         128
94 #define B_OK_BUTTON           1
95 #define B_APPLY_BUTTON        2
96 #define B_CANCEL_BUTTON       3
97 #define B_HELP_BUTTON         4
98
99 #define ERR2   ((char *)GETMESSAGE(11, 2, "The backdrop portion of the Style Manager\n\
100 will not operate because there are no backdrop\nfiles available. Check $HOME/.dt/errorlog."))
101
102 /*+++++++++++++++++++++++++++++++++++++++*/
103 /* Internal Functions                    */
104 /*+++++++++++++++++++++++++++++++++++++++*/
105
106 static int CreateBackdropDialog( Widget parent) ;
107 static void MoreBitmaps( void ) ;
108 static ReadBitmaps( void ) ;
109 static Boolean CreatePixmaps( void ) ;
110 static ReadBitmapDirectory( char *dir ) ;
111 static void DrawBitmap( 
112                         Widget w,
113                         XtPointer client_data,
114                         XtPointer call_data) ;
115 static void SizeBitmap( 
116                         Widget w,
117                         XtPointer client_data,
118                         XtPointer call_data) ;
119 static XmString * MakeListStrings( void ) ;
120 static void FreeListStrings( XmString *listPtr) ;
121 static void ListCB( 
122                         Widget w,
123                         XtPointer client_data,
124                         XtPointer call_data) ;
125 static void ButtonCB( 
126                         Widget w,
127                         XtPointer client_data,
128                         XtPointer call_data) ;
129 static void GetColors( void ) ;
130 static void FreeAll( void ) ;
131 static void _DtMapCB( 
132                         Widget w,
133                         XtPointer client_data,
134                         XtPointer call_data) ;
135
136
137 /*+++++++++++++++++++++++++++++++++++++++*/
138 /* Internal Variables                    */
139 /*+++++++++++++++++++++++++++++++++++++++*/
140
141 typedef struct {
142     Widget   drawnButton;
143     char   **dirList;
144     int      dirCount;
145     char   **tmpBitmapNames;
146     int      tmpNumBitmaps;
147     int      tmpMaxNumBitmaps;
148     char   **bitmapNames;
149     char   **bitmapDescs;
150     Pixmap  *bitmaps;
151     int      numBitmaps;
152     int      maxNumBitmaps;
153     int      selected;
154     GC       gc;
155     int      width, height;
156     int      shadow;
157     Pixel    fg, bg;
158     char    *errStr;
159     char     noBitmaps;
160     Boolean  newColors;
161 } Backdrops, *BackdropsPtr;
162 static Backdrops backdrops; 
163
164 static saveRestore save = {FALSE, 0, };
165 char *BACKDROPSDLG = "backdropsDialog";
166
167 /*
168  *   copy of the system backdrop description file for the 
169  *   current locale in xrm form
170  */
171 static XrmDatabase sys_bd_DB = NULL;
172
173 /*
174  *   copy of the admin backdrop description file for the 
175  *   current locale in xrm form
176  */
177 static XrmDatabase adm_bd_DB = NULL;
178
179 /*
180  *   copy of the user's home backdrop description file for the 
181  *   current locale in xrm form
182  */
183 static XrmDatabase hm_bd_DB = NULL;
184
185 /*
186  *   final combination of the admin & system data bases 
187  */
188 static XrmDatabase bd_DB = NULL;
189
190
191
192 /*+++++++++++++++++++++++++++++++++++++++*/
193 /* build_dirList                         */
194 /*+++++++++++++++++++++++++++++++++++++++*/
195
196 char ** 
197 build_dirList(char * dirStr, 
198                  int * count)
199 {
200    char tokenSep[] = ":";
201    char * token;
202    char ** dirList = NULL;
203    register int i = 0;
204    char * tmpStr;
205    int len = strlen(dirStr);
206    *count = 0;
207
208    tmpStr = (char *)XtCalloc(1, len + 1);
209    strcpy(tmpStr, dirStr);
210    token = strtok(tmpStr, tokenSep);
211    while(token != NULL)
212      {
213        ++(i);
214        token = strtok(NULL, tokenSep);
215      }
216
217    if (i == 0)
218        return (NULL);
219
220    dirList = (char **) XtCalloc(1, i * sizeof(char *));
221    if( dirList )
222      {
223        strcpy(tmpStr, dirStr); 
224        token = strtok(tmpStr, tokenSep);
225        *count=0;
226        while(token != NULL)
227          {
228            dirList[*count] = (char *) XtCalloc(1, strlen( token ) + 1);
229            strcpy(dirList[*count], token);
230            token = strtok(NULL, tokenSep);
231            ++(*count);
232          }
233      }
234
235    XtFree ((char *) tmpStr);
236    return(dirList);
237  }
238
239
240
241 /*+++++++++++++++++++++++++++++++++++++++*/
242 /* free_dirList                          */
243 /*+++++++++++++++++++++++++++++++++++++++*/
244
245 void
246 free_dirList(char ** dirList, 
247                     int count)
248
249 {
250   register int   i;
251
252   if (dirList == NULL)
253     return;
254   for (i=0; i<count; i++)
255     XtFree((char *) dirList[i]);
256   
257   XtFree ((char *) dirList);
258 }
259
260
261 /************************************************************************
262  *  SelectCurrentBackdrop() - Selects current backdrop in list
263  *
264  ************************************************************************/
265 void SelectCurrentBackdrop(callback)
266 {
267     DtWsmWorkspaceInfo   *wInfo=NULL;
268     Atom             aWS;
269     Widget list;
270     char *backdropName;
271     int i;
272
273     if ((DtWsmGetCurrentWorkspace (style.display, style.root, &aWS) 
274                 != Success) ||
275         (DtWsmGetWorkspaceInfo (style.display, style.root, aWS, &wInfo)
276                 != Success))
277     {
278       return;
279     }
280       
281     list = XtNameToWidget(style.backdropDialog, "*bitmapList");
282
283     backdropName = XmGetAtomName(style.display, wInfo->backdropName);
284
285     for (i = 0; i < backdrops.numBitmaps; i++) {
286       if (strcmp(backdrops.bitmapNames[i], backdropName) == 0) {
287         XmListSelectPos (list, i + 1, callback);
288         XmListSetPos(list, i + 1);
289         backdrops.selected = i;
290       }
291     }
292
293     XtFree((char *) backdropName);
294     XtFree((char *) wInfo);
295 }
296
297 /************************************************************************
298  *  BackdropDialog() - Create backdrop selection dialog first time up.
299  *           If it has already been created, map it.
300  ************************************************************************/
301 void 
302 BackdropDialog(
303         Widget parent )
304 {
305     int i;
306     
307     if (style.backdropDialog == NULL) 
308     {
309         _DtTurnOnHourGlass(parent);  
310         if (!CreateBackdropDialog(parent)) { 
311            _DtTurnOffHourGlass(parent);  
312            return;
313         }
314         SelectCurrentBackdrop(False);
315         XtManageChild(style.backdropDialog);
316         XSync(style.display, 0);
317         XmUpdateDisplay(style.backdropDialog);
318         _DtTurnOffHourGlass(parent);  
319
320     }
321     else
322     {
323         SelectCurrentBackdrop(True);
324         XtManageChild(style.backdropDialog);
325         raiseWindow(XtWindow(XtParent(style.backdropDialog)));
326         XmUpdateDisplay(style.backdropDialog);
327     }
328 }
329
330
331 /************************************************************************
332  *   CreateBackdropDialog()
333  *           Create the Backdrop Dialog
334  ************************************************************************/
335 static int 
336 CreateBackdropDialog(
337         Widget parent )
338 {
339     register int     i, n;
340     Arg              args[20];
341     Widget           mainForm;
342     Widget           list;
343     XmString         strings[NUM_LABELS+1];
344     XmString        *listStrings;
345     char            *bd_desc;
346     char            *lang;
347
348
349     if (backdrops.noBitmaps) 
350     {
351         ErrDialog (backdrops.errStr, style.shell);
352         return 0;
353     }
354
355     /* initialize backdrop data */
356     backdrops.bitmapNames = NULL;
357     backdrops.bitmaps = NULL;
358     backdrops.numBitmaps = 0;
359     backdrops.maxNumBitmaps = 100;
360     backdrops.selected = -1;
361     backdrops.gc = NULL;
362     backdrops.errStr = NULL;
363     backdrops.shadow = 2;
364     backdrops.width = 200 - 2*backdrops.shadow;
365     backdrops.height = 200 - 2*backdrops.shadow;
366     backdrops.newColors = True;
367
368     
369     /* load the backdrop description data base for the given locale*/
370     /* from that locale's description file from the system location */
371     lang = setlocale (LC_CTYPE,NULL);
372
373 #ifdef hpux      /* hpux-specific parsing of the locale string */
374                  /* The following code is identical to the
375                     ExtractLocaleName function in WmResParse.c
376                     from dtwm
377                  */
378 #define MAXLOCALE       64      /* buffer size of locale name */
379
380 {   char           *start;
381     char           *end;
382     int             len;
383     static char     buf[MAXLOCALE];
384
385     /*  If lang has a substring ":<category>;", extract <category>
386      *  from the first such occurrence as the locale name.
387      */
388
389     start = lang;
390     if (start = strchr (lang, ':')) {
391         start++;
392         if (end = strchr (start, ';')) {
393             len = end - start;
394             strncpy(buf, start, len);
395             *(buf + len) = '\0';
396             lang = buf;
397       }
398     }
399 }
400 #endif  /* hpux */
401
402     bd_desc = (char *)XtMalloc(strlen("/usr/dt/backdrops/desc.") + strlen(lang) + 1);
403     strcpy (bd_desc,"/usr/dt/backdrops/desc.");
404     strcat (bd_desc, lang);
405     if(sys_bd_DB = XrmGetFileDatabase (bd_desc))
406         XrmMergeDatabases(sys_bd_DB, &bd_DB);
407     XtFree(bd_desc);
408     
409     /* load the backdrop description data base for the given locale*/
410     /* from that locale's description file from the admin location */
411     bd_desc = (char *)XtMalloc(strlen("/etc/dt/backdrops/desc.") + strlen(lang) + 1);
412     strcpy (bd_desc,"/etc/dt/backdrops/desc.");
413     strcat (bd_desc, lang);
414     if (adm_bd_DB = XrmGetFileDatabase (bd_desc))
415         XrmMergeDatabases(adm_bd_DB, &bd_DB);
416     XtFree(bd_desc);
417
418     /* load the backdrop description from the user's .dt/backdrops directory */
419     /* regardless of locale */
420     bd_desc = (char *)XtMalloc(strlen(style.home) + strlen("/.dt/backdrops/desc.backdrops") + 1);
421     strcpy (bd_desc, style.home);
422     strcat (bd_desc, "/.dt/backdrops/desc.backdrops");
423     if (hm_bd_DB = XrmGetFileDatabase (bd_desc))
424         XrmMergeDatabases(hm_bd_DB, &bd_DB);
425     XtFree(bd_desc);
426
427     /* Set up DialogBox button labels. */
428     strings[0] = XmStringCreateLocalized ((String) _DtOkString);
429     strings[1] = XmStringCreateLocalized ((String) _DtApplyString);
430     strings[2] = XmStringCreateLocalized ((String) _DtCloseString);
431     strings[3] = XmStringCreateLocalized ((String) _DtHelpString);
432
433     /* saveRestore
434      * Note that save.poscnt has been initialized elsewhere.
435      * save.posArgs may contain information from restoreBackdrop().*/
436
437     /* create the dialog box with shell */
438
439     XtSetArg (save.posArgs[save.poscnt], XmNbuttonCount, NUM_LABELS+1);
440                                                                  save.poscnt++;
441     XtSetArg (save.posArgs[save.poscnt], XmNbuttonLabelStrings, strings);
442                                                                  save.poscnt++;
443     XtSetArg (save.posArgs[save.poscnt], XmNdefaultPosition, False);
444                                                                  save.poscnt++;
445     XtSetArg (save.posArgs[save.poscnt], XmNallowOverlap, False);
446                                                                  save.poscnt++;
447     style.backdropDialog = __DtCreateDialogBoxDialog (parent, BACKDROPSDLG,
448                                                      save.posArgs, save.poscnt);
449     XtAddCallback(style.backdropDialog, XmNcallback, ButtonCB, NULL);
450     XtAddCallback(style.backdropDialog, XmNmapCallback, _DtMapCB, parent);
451     XtAddCallback(style.backdropDialog, XmNhelpCallback,
452             (XtCallbackProc)HelpRequestCB, (XtPointer)HELP_BACKDROP_DIALOG);
453
454     /* free compound strings now */
455     XmStringFree (strings[0]);
456     XmStringFree (strings[1]);
457     XmStringFree (strings[2]);
458     XmStringFree (strings[3]);
459
460     n = 0;
461     XtSetArg (args[n], XmNtitle, ((char *)GETMESSAGE(11, 12, "Style Manager - Backdrop"))); n++;
462     XtSetArg (args[n], XmNuseAsyncGeometry, True); n++;
463     XtSetValues (XtParent(style.backdropDialog), args, n);
464
465     /*  get bitmap data */
466     if (!ReadBitmaps())  return 0;         /* uses style.backdropDialog */
467
468     /* create the form to go in to dialog box as the work area */
469     n = 0;
470     XtSetArg(args[n], XmNhorizontalSpacing, style.horizontalSpacing); n++;
471     XtSetArg(args[n], XmNverticalSpacing, style.verticalSpacing); n++;
472     XtSetArg (args[n], XmNchildType, XmWORK_AREA);  n++;
473
474     XtSetArg (args[n], XmNallowOverlap, False);  n++;
475     mainForm = XmCreateForm (style.backdropDialog, "backdropsForm", args, n);
476
477     /* create the scrolled list of bitmap names... first create XmStrings */
478     listStrings = MakeListStrings ();
479     n = 0;
480     XtSetArg (args[n], XmNautomaticSelection, True);              n++;
481     XtSetArg (args[n], XmNselectionPolicy, XmBROWSE_SELECT);      n++;
482     XtSetArg (args[n], XmNitems, listStrings);                    n++;
483     XtSetArg (args[n], XmNitemCount, backdrops.numBitmaps);       n++;
484     list = XmCreateScrolledList (mainForm, "bitmapList", args, n);
485     XtAddCallback (list, XmNbrowseSelectionCallback, ListCB, (XtPointer)NULL);
486     FreeListStrings (listStrings);            /* after list has copied */
487
488     /* set up attachments for scrolled list itself */
489     n = 0;
490     XtSetArg (args[n], XmNtopAttachment, XmATTACH_FORM);          n++;
491     XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM);        n++;
492     XtSetArg (args[n], XmNbottomAttachment, XmATTACH_FORM);       n++;
493     XtSetValues (XtParent(list), args, n);
494
495     /*   Create drawing area for the bitmap  */
496     n = 0;
497     XtSetArg (args[n], XmNshadowType, XmSHADOW_IN);                     n++;
498     XtSetArg (args[n], XmNshadowThickness, backdrops.shadow);           n++;
499     XtSetArg (args[n], XmNhighlightThickness, 0);                       n++;
500     XtSetArg (args[n], XmNrightAttachment, XmATTACH_WIDGET);            n++;
501     XtSetArg (args[n], XmNrightWidget, XtParent(list));                 n++;
502     XtSetArg (args[n], XmNtopAttachment, XmATTACH_FORM);                n++;
503     XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM);               n++;
504     XtSetArg (args[n], XmNbottomAttachment, XmATTACH_FORM);             n++;
505     XtSetArg (args[n], XmNborderWidth, 0);                              n++;
506     XtSetArg (args[n], XmNwidth, backdrops.width+2*backdrops.shadow);   n++;
507     XtSetArg (args[n], XmNheight, backdrops.height+2*backdrops.shadow); n++;
508     XtSetArg (args[n], XmNtraversalOn, False);                          n++;  
509     backdrops.drawnButton = XmCreateDrawnButton (mainForm, "bitmap", args, n);
510     XtAddCallback (backdrops.drawnButton, XmNexposeCallback, DrawBitmap, NULL);
511     XtAddCallback (backdrops.drawnButton, XmNresizeCallback, SizeBitmap, NULL);
512
513     /* manage all of the widgets */
514     XtManageChild (mainForm);
515     XtManageChild (backdrops.drawnButton);
516     XtManageChild (list);
517
518     return 1;
519 }
520
521
522 /************************************************************************
523  *   MoreBitmaps()
524  *           Create space for more bitmap entries
525  ************************************************************************/
526 static void 
527 MoreBitmaps( void )
528 {
529     int   newSize;
530
531     /* allocate space for icon names */
532     newSize =  (backdrops.maxNumBitmaps + 100) * sizeof(char *);
533     backdrops.bitmapNames = (char **) XtRealloc((char *)backdrops.bitmapNames, 
534                                                 newSize);
535
536     /* now allocate new bitmap space */
537     newSize =  (backdrops.maxNumBitmaps + 100) * sizeof(Pixmap);
538     backdrops.bitmaps = (Pixmap *)XtRealloc((char *)backdrops.bitmaps, newSize);
539
540     backdrops.maxNumBitmaps += 100;
541 }
542
543 /************************************************************************
544  * cmpstringp()
545  * qsort() sort function, used for sorting bitmap names into alphabetical order
546  * can't use strcmp() due to char** rather than char*
547  ************************************************************************/
548 static int
549 cmpstringp(const void *p1, const void *p2)
550 {
551   return strcmp(*(char * const *) p1, *(char * const *) p2);
552 }
553
554 /************************************************************************
555  *   ReadBitmaps()
556  *   Create an array of bitmaps by reading backdrop directories in the
557  *   following order overriding any duplicates:
558  *   1) Read the system location /usr/dt/backdrops
559  *   2) Read the admin location /etc/dt/backdrops
560  *   3) Read the directories specified by the backdropDirectories
561  *      resource.
562  *   4) Read the user's home directory /$HOME/.dt/backdrops.
563  ************************************************************************/
564 static 
565      ReadBitmaps( void )
566 {
567   int            status;
568   Pixmap         tmpPix = 0;
569   int            width, height, x, y;
570   Window         win;
571   int            num;
572   register int   i;   
573   char          *string;
574   /* allocate space for temporary bitmap info */
575   backdrops.tmpBitmapNames = (char **)XtCalloc(100, sizeof(char *));
576   backdrops.tmpMaxNumBitmaps = 100;
577   backdrops.tmpNumBitmaps = 0;
578   
579   /* read system backdrop directory */
580     ReadBitmapDirectory("/usr/dt/backdrops");
581   /* read sys admin backdrop directory */
582   ReadBitmapDirectory("/etc/dt/backdrops");
583   
584   /* Parse the backdropDirectories resource to get the individual directories */
585   if (style.xrdb.backdropDir)
586     {
587       backdrops.dirList = build_dirList(style.xrdb.backdropDir, &backdrops.dirCount);
588       
589       /* compile the list of bitmaps */
590       for (i=0; i<backdrops.dirCount; i++)
591         ReadBitmapDirectory(backdrops.dirList[i]);
592     }
593   
594   /* read the directory $HOME/.dt/backdrops */
595   string = (char *)XtMalloc(strlen(style.home) + strlen("/.dt/backdrops") + 1);
596   sprintf(string, "%s/.dt/backdrops", style.home);
597   ReadBitmapDirectory(string);
598   if (string != NULL)
599     XtFree(string);
600
601   if (backdrops.tmpNumBitmaps == 0)
602     {
603       /* give error dialog, free space, and return */
604       backdrops.errStr = (char *)XtMalloc(strlen(ERR2) + 1);
605       sprintf(backdrops.errStr, "%s", ERR2);
606       ErrDialog (backdrops.errStr, style.shell); 
607       FreeAll();      
608       free_dirList(backdrops.dirList, backdrops.dirCount);
609       return 0;
610     }
611
612   /* Sort the list into alphanetical order */
613   qsort(backdrops.tmpBitmapNames, backdrops.tmpNumBitmaps, sizeof(char *), cmpstringp);
614   
615   /* get the fg/bg colors from Dtwm */
616   if (backdrops.newColors)
617     {
618       GetColors();
619       backdrops.newColors = False;
620     }   
621   
622     /* create all the pixmaps */
623   if (!CreatePixmaps())
624     {
625       /* give error dialog, free space, and return */
626       backdrops.errStr = (char *)XtMalloc(strlen(ERR2) + 1);
627       sprintf(backdrops.errStr, "%s", ERR2);
628       ErrDialog (backdrops.errStr, style.shell); 
629       FreeAll();  
630       free_dirList(backdrops.dirList, backdrops.dirCount);
631       return 0;
632     }
633   
634   
635   if (backdrops.selected == -1) backdrops.selected = 0;   
636   
637   return 1;
638 }
639
640
641
642 /************************************************************************
643  *   CreatePixmaps()
644  *           Create the pixmpas in the backdrop list
645              with workprocs 10 at a time
646  ************************************************************************/
647 static Boolean
648 CreatePixmaps( void )
649
650 {
651     static int     pixmapsCreated=0;
652     int            i;
653     Pixmap         tmpPixmap;
654     
655     backdrops.numBitmaps = 0;
656
657     /* allocate space for real bitmap info */
658     backdrops.bitmapNames = (char **)XtCalloc(100, sizeof(char *));
659     backdrops.bitmaps = (Pixmap *)XtCalloc(100, sizeof(Pixmap));
660
661     for (i=0; i<backdrops.tmpNumBitmaps; i++)
662     {
663         tmpPixmap = XmGetPixmap (style.screen, 
664                                  backdrops.tmpBitmapNames[i], 
665                                  backdrops.fg, backdrops.bg); 
666         if (tmpPixmap != XmUNSPECIFIED_PIXMAP)
667         {
668             if (backdrops.numBitmaps == backdrops.maxNumBitmaps)
669                 MoreBitmaps();
670
671             backdrops.bitmapNames[backdrops.numBitmaps] = 
672                     backdrops.tmpBitmapNames[i];
673             backdrops.bitmaps[backdrops.numBitmaps] = tmpPixmap;
674  
675             backdrops.numBitmaps++;
676         }
677
678     }
679     if (backdrops.numBitmaps)
680         return(True);
681     else
682         return(False);
683
684 }
685
686
687 /************************************************************************
688  *   ReadBitmapDirectory()
689  *           Create an array of bitmap names overriding duplicates
690  ************************************************************************/
691 static
692 ReadBitmapDirectory( 
693     char *dir )
694
695 {
696     DIR            *dirp;
697     struct dirent  *filep;
698     int             i;
699     Boolean         duplicate;
700     char           *name;
701     int             stat_result;
702     struct stat     stat_buf;
703     char           *statPath, *pStatPath;
704     int             newSize;
705
706     /* open the backdrops directory */
707     if ((dirp = opendir(dir)) == NULL)
708     {
709         /* print message to errorlog, free space, and return */
710       return 0;
711     }
712     
713     /* create string to contain complete path */
714     statPath = (char *) XtMalloc(strlen(dir) + MAX_STR_LEN + 2);
715     strcpy (statPath, dir);
716     strcat (statPath, "/");
717     pStatPath = statPath + strlen(statPath);
718
719     filep = readdir(dirp);
720
721     while (filep != NULL)
722     {
723         /* append filename to stat path */
724         strcpy (pStatPath, filep->d_name);
725
726         /* stat the file */
727         if ((stat_result = stat (statPath, &stat_buf)) != 0)
728         {
729             filep = readdir(dirp);
730             continue;
731         }
732             
733         /* skip directories */
734         if ((stat_buf.st_mode & S_IFMT) == S_IFDIR)
735         {
736             filep = readdir(dirp);
737             continue; 
738         }
739
740         
741         /* strip suffix off filename */
742         name = (char *) XtMalloc(strlen(filep->d_name) + 1);
743         strcpy (name, filep->d_name);
744         (void)strtok(name, ".");
745
746         /* check for duplicates */
747         duplicate = 0;
748         for (i=0; i<backdrops.tmpNumBitmaps; i++)
749         {
750             if (!strcmp(backdrops.tmpBitmapNames[i], name))
751             {
752                 duplicate = 1;
753                 break;                
754             }
755         }
756         
757         if (!duplicate)
758         {
759             /* add to the temporary bitmap list */
760
761             if (backdrops.tmpNumBitmaps == backdrops.tmpMaxNumBitmaps)
762             {
763                 /* allocate space for more temporary bitmap info */
764                 newSize =  (backdrops.tmpMaxNumBitmaps + 100) * sizeof(char *);
765                 backdrops.tmpBitmapNames = 
766                     (char **)XtRealloc((char *)backdrops.tmpBitmapNames, newSize);
767                 backdrops.tmpMaxNumBitmaps += 100;
768             }
769
770             backdrops.tmpBitmapNames[backdrops.tmpNumBitmaps] = 
771                 (char *) XtMalloc(strlen(name)+1);
772             strcpy (backdrops.tmpBitmapNames[backdrops.tmpNumBitmaps], name);
773
774             backdrops.tmpNumBitmaps++;
775         }
776
777         filep = readdir(dirp);
778         XtFree(name);
779     }
780
781     XtFree(statPath);
782
783
784     closedir (dirp);
785     return 1;
786 }
787
788
789 /************************************************************************
790  *   DrawBitmap()
791  *           This is the exposeCallback for the bitmap drawing area.
792  ************************************************************************/
793 static void 
794 DrawBitmap(
795         Widget w,
796         XtPointer client_data,
797         XtPointer call_data )
798 {
799     XGCValues     gcValues;
800     Arg           args[3];
801         
802     if (backdrops.selected == -1)
803         return;
804
805     if (backdrops.newColors)
806     {
807         GetColors();
808
809         /* we could keep track of which tile pixmaps need to be updated
810            since the last workspace change, but for now simply regenerate 
811            each pixmap as it is selected after a workspace change has 
812            occurred */
813
814         /* backdrops.newColors = False; */
815     }
816
817     if (backdrops.gc == NULL)
818     {
819         gcValues.background = backdrops.bg;
820         gcValues.foreground = backdrops.fg;
821         gcValues.fill_style = FillTiled;
822         gcValues.tile = backdrops.bitmaps[backdrops.selected];
823
824         backdrops.gc = XCreateGC (style.display, XtWindow(w), 
825                                 GCForeground | GCBackground | 
826                                 GCTile | GCFillStyle, &gcValues);
827     }
828
829     XFillRectangle (style.display, XtWindow(w), backdrops.gc, backdrops.shadow,
830                     backdrops.shadow, backdrops.width, backdrops.height);
831 }
832
833
834 /************************************************************************
835  *   SizeBitmap()
836  *           This is the resizeCallback for the bitmap drawing area.
837  ************************************************************************/
838 static void 
839 SizeBitmap(
840         Widget w,
841         XtPointer client_data,
842         XtPointer call_data )
843 {
844     backdrops.width = XtWidth(w) - 2*backdrops.shadow;
845     backdrops.height = XtHeight(w) - 2*backdrops.shadow;
846 }
847
848
849 /************************************************************************
850  *   MakeListStrings()
851  *           Make XmStrings from the bitmap descriptions, to pass into list.
852  *  
853  ************************************************************************/
854 static XmString * 
855 MakeListStrings( void )
856 {
857     int         i;
858     XmString   *list;
859     char       *name_str;
860     char       *class_str;
861     char       *str_type_return;
862     XrmValue    value_return;
863     
864     /* allocate space for bitmap descriptions */
865     backdrops.bitmapDescs = (char **)XtCalloc(backdrops.numBitmaps, sizeof(char *));
866     
867     for (i=0; i<backdrops.numBitmaps; i++)
868       {
869         if (bd_DB !=NULL)
870           {
871             name_str = (char *) XtMalloc(strlen("backdrops.") + 
872                                          strlen(backdrops.bitmapNames[i]) +
873                                          strlen(".desc") + 1);
874             
875             class_str = (char *) XtMalloc(strlen("Backdrops.") + 
876                                           strlen(backdrops.bitmapNames[i]) + 
877                                           strlen(".Desc") + 1);
878             strcpy(name_str, "backdrops.");
879             strcpy(class_str, "Backdrops.");
880             strcat(name_str, backdrops.bitmapNames[i]);
881             strcat(class_str, backdrops.bitmapNames[i]);
882             strcat(name_str, ".desc");
883             strcat(class_str, ".Desc");
884
885             if (XrmGetResource (bd_DB, name_str, class_str, &str_type_return, &value_return))
886               {
887                 /* make copy of resource value */
888                 backdrops.bitmapDescs[i] = (char *) XtMalloc(value_return.size + 1);
889                 strcpy (backdrops.bitmapDescs[i], value_return.addr);
890               }    
891             else
892               {   
893                 backdrops.bitmapDescs[i] = (char *) XtMalloc(strlen(backdrops.bitmapNames[i]) + 1);
894                 strcpy(backdrops.bitmapDescs[i], backdrops.bitmapNames[i]);
895               }
896           }
897         else
898           {       
899             backdrops.bitmapDescs[i] = (char *) XtMalloc(strlen(backdrops.bitmapNames[i]) + 1);
900             strcpy(backdrops.bitmapDescs[i], backdrops.bitmapNames[i]);
901           }
902       }
903
904     list = (XmString *) XtCalloc(backdrops.numBitmaps, sizeof(XmString));
905     
906     for (i = 0; i < backdrops.numBitmaps; i++)
907     {
908         list[i] = XmStringCreateLocalized (backdrops.bitmapDescs[i]);
909     }
910
911     return (list);
912 }
913
914
915 /************************************************************************
916  *   FreeListStrings()
917  *           Free XmStrings from the bitmap names, passed into list.
918  ************************************************************************/
919 static void 
920 FreeListStrings(
921         XmString *listPtr )
922 {
923     int         i;
924     int         n;
925     XmString   *list = listPtr;
926
927     for (i = 0; i < backdrops.numBitmaps; i++)
928     {
929         if (list[i]) XmStringFree(list[i]);
930     }
931     XtFree ((char *)list);
932 }
933
934
935 /************************************************************************
936  *   ListCB()
937  *           Get the bitmap selected from the list
938  ************************************************************************/
939 static void 
940 ListCB(
941         Widget w,
942         XtPointer client_data,
943         XtPointer call_data )
944 {
945     XmListCallbackStruct  *cb = (XmListCallbackStruct *)call_data;
946
947     backdrops.selected = cb->item_position - 1;
948
949     XSetTile (style.display, backdrops.gc, 
950               backdrops.bitmaps[backdrops.selected]);
951
952     DrawBitmap (backdrops.drawnButton, NULL, NULL);
953 }
954
955
956
957 /************************************************************************
958  *   ButtonCB()
959  *          
960  ************************************************************************/
961 static void 
962 ButtonCB(
963         Widget w,
964         XtPointer client_data,
965         XtPointer call_data )
966 {
967     int      n, num;
968     Arg      args[MAX_ARGS];
969
970     DtDialogBoxCallbackStruct *cb = (DtDialogBoxCallbackStruct *) call_data;
971
972     switch (cb->button_position)
973     {
974       case B_APPLY_BUTTON:
975           /* send message to update backdrop */
976
977           num = backdrops.selected;
978
979           _DtWsmChangeBackdrop(style.display, style.root, 
980                              backdrops.bitmapNames[num], 
981                              backdrops.bitmaps[num]);
982           break;
983
984       case B_OK_BUTTON:  
985           /* send message to update backdrop */
986
987           num = backdrops.selected;
988
989           _DtWsmChangeBackdrop(style.display, style.root,
990                              backdrops.bitmapNames[num],
991                              backdrops.bitmaps[num]);
992           XtUnmanageChild(w);
993           break;
994
995       case B_CANCEL_BUTTON:            /* close */
996           XtUnmanageChild(w);
997           break;
998
999       case B_HELP_BUTTON:
1000           XtCallCallbacks(style.backdropDialog, XmNhelpCallback, (XtPointer)NULL);
1001           break;
1002
1003       default:
1004           break;
1005     }
1006 }
1007
1008
1009 /************************************************************************
1010  *   CheckWorkspace()
1011  *           Workspace may have changed, so get current workspace
1012  *           colors and draw the backdrop bitmap
1013  *          
1014  ************************************************************************/
1015 void 
1016 CheckWorkspace( void )
1017 {
1018     backdrops.newColors = True;         /* need to get new colors */
1019     if (style.backdropDialog && XtIsManaged(style.backdropDialog))
1020     {
1021         DrawBitmap (backdrops.drawnButton, NULL, NULL);
1022     }
1023 }
1024
1025
1026 /************************************************************************
1027  *   GetColors()
1028  *           Get current workspace colors, and update GC if needed
1029  *          
1030  ************************************************************************/
1031 static void 
1032 GetColors( void )
1033 {
1034     DtWsmWorkspaceInfo   *wInfo=NULL;
1035     unsigned long    num=0;
1036     Pixel            fg, bg;
1037     XGCValues        gcValues;
1038     Atom             aWS;
1039
1040     if ((DtWsmGetCurrentWorkspace (style.display, style.root, &aWS) 
1041                 == Success) &&
1042         (DtWsmGetWorkspaceInfo (style.display, style.root, aWS, &wInfo)
1043                 == Success))
1044     {
1045         backdrops.bg = wInfo->bg;
1046         backdrops.fg = wInfo->fg;
1047         DtWsmFreeWorkspaceInfo (wInfo);
1048     }
1049     else 
1050     {
1051         backdrops.bg = 0;
1052         backdrops.fg = 1;
1053     }
1054
1055     if (backdrops.gc)      /* update the gc if there is one */
1056     {
1057         gcValues.background = backdrops.bg;
1058         gcValues.foreground = backdrops.fg;
1059
1060         /* free old pixmap */
1061         XmDestroyPixmap(style.screen, 
1062                         backdrops.bitmaps[backdrops.selected]);
1063
1064         /* allocate new pixmap */
1065         backdrops.bitmaps[backdrops.selected] = 
1066             XmGetPixmap (style.screen, 
1067                          backdrops.bitmapNames[backdrops.selected], 
1068                          backdrops.fg, backdrops.bg); 
1069
1070         gcValues.tile = backdrops.bitmaps[backdrops.selected];
1071
1072         XChangeGC (style.display, backdrops.gc, 
1073                    GCForeground | GCBackground | GCTile, &gcValues);
1074     }
1075 }
1076
1077
1078 /************************************************************************
1079  * FreeAll()
1080  *        Free some space that was allocated for backdrops
1081  ************************************************************************/
1082 static void 
1083 FreeAll( void )
1084 {
1085     int i;
1086
1087     /* set no bitmaps flag, so we won't try to get them next time */ 
1088     backdrops.noBitmaps = 1;
1089
1090     /* free temporary list of backdrop names */
1091     for (i = 0; i < backdrops.tmpNumBitmaps; i++)
1092         if (backdrops.tmpBitmapNames[i]) 
1093             XtFree(backdrops.tmpBitmapNames[i]);
1094     XtFree ((char *)backdrops.tmpBitmapNames);
1095     XtFree ((char *)backdrops.bitmapNames);
1096
1097     /* free backdrop bitmaps */
1098     for (i = 0; i < backdrops.numBitmaps; i++) {
1099         if (backdrops.bitmaps[i]) 
1100             XFreePixmap (style.display, backdrops.bitmaps[i]);
1101     if (backdrops.numBitmaps)
1102         XtFree((char *)backdrops.bitmaps);  
1103     }
1104
1105     /* destory widgets (via first parent) */
1106     XtDestroyWidget (XtParent(style.backdropDialog));
1107     style.backdropDialog = NULL;
1108 }
1109
1110
1111 /************************************************************************
1112  * _DtMapCB
1113  *
1114  ************************************************************************/
1115 static void 
1116 _DtMapCB(
1117         Widget w,
1118         XtPointer client_data,
1119         XtPointer call_data )
1120 {
1121
1122     DtWsmRemoveWorkspaceFunctions(style.display, XtWindow(XtParent(w)));
1123
1124     if (!save.restoreFlag)
1125         putDialog((Widget)client_data, w);
1126
1127     XtRemoveCallback(style.backdropDialog, XmNmapCallback, _DtMapCB, NULL);
1128 }
1129
1130
1131 /************************************************************************
1132  * restoreBackdrop()
1133  *
1134  * restore any state information saved with saveBackdrop.
1135  * This is called from restoreSession with the application
1136  * shell and the special xrm database retrieved for restore.
1137  ************************************************************************/
1138 void 
1139 restoreBackdrop(
1140         Widget shell,
1141         XrmDatabase db )
1142 {
1143     XrmName xrm_name[5];
1144     XrmRepresentation rep_type;
1145     XrmValue value;
1146
1147     xrm_name [0] = XrmStringToQuark (BACKDROPSDLG);
1148     xrm_name [2] = 0;
1149
1150     /* get x position */
1151     xrm_name [1] = XrmStringToQuark ("x");
1152     if (XrmQGetResource (db, xrm_name, xrm_name, &rep_type, &value)) {
1153         XtSetArg (save.posArgs[save.poscnt], XmNx, atoi((char *)value.addr)); 
1154         save.poscnt++;
1155         save.restoreFlag = True;
1156     }
1157
1158     /* get y position */
1159     xrm_name [1] = XrmStringToQuark ("y");
1160     if (XrmQGetResource (db, xrm_name, xrm_name, &rep_type, &value)) {
1161         XtSetArg (save.posArgs[save.poscnt], XmNy, atoi((char *)value.addr)); 
1162         save.poscnt++;
1163     }
1164
1165     /* get width */
1166     xrm_name [1] = XrmStringToQuark ("width");
1167     if (XrmQGetResource (db, xrm_name, xrm_name, &rep_type, &value)) {
1168         XtSetArg(save.posArgs[save.poscnt], XmNwidth, atoi((char *)value.addr));
1169         save.poscnt++;
1170     }
1171
1172     /* get height */
1173     xrm_name [1] = XrmStringToQuark ("height");
1174     if (XrmQGetResource (db, xrm_name, xrm_name, &rep_type, &value)) {
1175         XtSetArg(save.posArgs[save.poscnt],XmNheight, atoi((char *)value.addr));
1176         save.poscnt++;
1177     }
1178
1179     xrm_name [1] = XrmStringToQuark ("ismapped");
1180     XrmQGetResource (db, xrm_name, xrm_name, &rep_type, &value);
1181     /* Are we supposed to be mapped? */
1182     if (strcmp(value.addr, "True") == 0)
1183         BackdropDialog(shell);
1184 }
1185
1186
1187 /************************************************************************
1188  * saveBackdrop()
1189  *
1190  * This routine will write out to the passed file descriptor any state
1191  * information this dialog needs.  It is called from saveSessionCB with the
1192  * file already opened.
1193  * All information is saved in xrm format.  There is no restriction
1194  * on what can be saved.  It doesn't have to be defined or be part of any
1195  * widget or Xt definition.  Just name and save it here and recover it in
1196  * restoreBackdrop.  The suggested minimum is whether you are mapped, and your
1197  * location.
1198  ************************************************************************/
1199 void 
1200 saveBackdrop(
1201         int fd )
1202 {
1203     Position x,y;
1204     Dimension width, height;
1205     char *bufr = style.tmpBigStr;     /* size=[1024], make bigger if needed */
1206     XmVendorShellExtObject  vendorExt;
1207     XmWidgetExtData         extData;
1208
1209     if (style.backdropDialog != NULL) 
1210     {
1211         if (XtIsManaged(style.backdropDialog))
1212             sprintf(bufr, "*backdropsDialog.ismapped: True\n");
1213         else
1214             sprintf(bufr, "*backdropsDialog.ismapped: False\n");
1215
1216         /* Get and write out the geometry info for our Window */
1217         x = XtX (XtParent(style.backdropDialog));
1218         y = XtY (XtParent(style.backdropDialog));
1219         width = XtWidth (style.backdropDialog);
1220         height = XtHeight (style.backdropDialog);
1221
1222         /* Modify x & y to take into account window mgr frames
1223          * This is pretty bogus, but I don't know a better way to do it.
1224          */
1225         extData = _XmGetWidgetExtData(style.shell, XmSHELL_EXTENSION);
1226         vendorExt = (XmVendorShellExtObject)extData->widget;
1227         x -= vendorExt->vendor.xOffset;
1228         y -= vendorExt->vendor.yOffset;
1229
1230         sprintf(bufr, "%s*backdropsDialog.x: %d\n", bufr, x);
1231         sprintf(bufr, "%s*backdropsDialog.y: %d\n", bufr, y);
1232         sprintf(bufr, "%s*backdropsDialog.width: %d\n", bufr, width);
1233         sprintf(bufr, "%s*backdropsDialog.height: %d\n", bufr, height);
1234         sprintf(bufr, "%s*backdropsDialog.selectedItemNum: %d\n", bufr, 
1235                 backdrops.selected);
1236         sprintf(bufr, "%s*backdropsDialog.selectedItem: %s\n", bufr, 
1237                 backdrops.bitmapNames[backdrops.selected]);
1238         write (fd, bufr, strlen(bufr));
1239     }
1240 }
1241
1242
1243