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