dtcm: Coverity 88353
[oweals/cde.git] / cde / programs / dtwm / WmBackdrop.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 libraries 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 /* 
24  * (c) Copyright 1987,1988,1989,1990,1992,1993,1994 HEWLETT-PACKARD COMPANY
25  * (c) Copyright 1993, 1994 International Business Machines Corp.
26  * (c) Copyright 1993, 1994 Sun Microsystems, Inc.
27  * (c) Copyright 1993, 1994 Novell, Inc.
28  */
29
30 #define BANDWIDTH               16
31 #define BOTTOM                   0
32 #define CHANGE_BACKDROP         (1L << 0)
33
34 #include "WmGlobal.h"
35 #include "WmResource.h"
36 #include "WmResNames.h"
37 #include "WmWrkspace.h"
38 #define DTWM_NEED_BACKBITS
39 #include "WmIBitmap.h"
40 #include "WmBackdrop.h"
41 #include "WmError.h"
42 #include "WmProperty.h"
43 #include <X11/Core.h>
44 #include <X11/StringDefs.h>
45 #include <X11/Intrinsic.h>
46 #include <X11/Xatom.h>
47 #include <X11/Shell.h>
48 #include <Dt/Message.h>
49 #include <Dt/DtP.h>
50 #include <Dt/WsmM.h>
51 #include <Xm/Xm.h>
52 #include <Xm/AtomMgr.h>
53 #include <errno.h>
54 #include <signal.h>
55 #include <stdio.h>
56 #include <sys/types.h>
57 #include <sys/stat.h>
58 #include <stdlib.h>
59 #include "WmIPC.h"      /* must be after DtP.h */
60
61 /**************************************
62         Functions
63 **/
64 /********    Static Function Declarations    ********/
65
66 static Pixmap WmXmGetPixmap2(
67                         Screen  *screen,
68                         char    *pchName,
69                         Pixel   fg,
70                         Pixel   bg
71                         ) ;
72
73 /********    End Static Function Declarations    ********/
74
75 /*
76  * externals
77  */
78 #include "WmImage.h"
79 #include "WmResParse.h"
80     
81 /********************************************
82         Globals
83 **/
84
85 /* maximum band width in tile units */
86 #define MAX_BAND_WIDTH  3
87 #define TOP_BAND_WIDTH  2
88
89 static int         bottom = BOTTOM;
90
91 static int         xa_NO_BACKDROP;
92
93
94
95 \f
96 /******************************<->*************************************
97  *
98  *  ChangeBackdrop ( pWS )
99  *
100  *
101  *  Description:
102  *  -----------
103  *
104  *  Inputs:
105  *  ------
106  * 
107  *  Outputs:
108  *  -------
109  *
110  *************************************<->***********************************/
111 void 
112 ChangeBackdrop(
113         WmWorkspaceData *pWS )
114 {
115     int iwin;
116
117
118     if (pWS->backdrop.window) 
119     {
120         if (pWS->backdrop.window == pWS->pSD->lastBackdropWin)
121         {
122             /* re-expose the window */
123             XClearWindow (DISPLAY, pWS->backdrop.window);
124         }
125         else
126         {
127             /*
128              * The old and new backdrops are different.
129              * Map the new backdrop and unmap the old.
130              */
131             XLowerWindow(DISPLAY, pWS->backdrop.window);
132
133             XMapWindow(DISPLAY, pWS->backdrop.window);
134         }
135     }
136
137     if (pWS->pSD->lastBackdropWin &&
138         (pWS->backdrop.window != pWS->pSD->lastBackdropWin))
139     {
140         XUnmapWindow(DISPLAY, pWS->pSD->lastBackdropWin);
141     }
142
143     pWS->pSD->lastBackdropWin = pWS->backdrop.window;
144
145 }
146
147
148 \f
149 /******************************<->*************************************
150  *
151  *  ProcessBackdropResources (pWS, callFlags)
152  *
153  *  Description:
154  *  -----------
155  *  Processes a backdrop for a particular workspace
156  *
157  *  Inputs:
158  *  ------
159  *  pWS  = pointer to screen data (backdrop data in particular)
160  *  callFlags =  processing flags
161  *           CHANGE_BACKDROP - the pixmap has already been created.
162  * 
163  *  Outputs:
164  *  -------
165  *  pWS = modifies the backdrop data that's part of this structure
166  *
167  *  Comments:
168  *  ---------
169  *  This routine interprets the backdrop.image field and converts
170  *  it from a string to the appropriate bitmap/pixmap images.
171  *  It also creates windows necessary for the backdrop.
172  *
173  *************************************<->***********************************/
174 void 
175 ProcessBackdropResources(
176         WmWorkspaceData *pWS,
177         unsigned long callFlags )
178 {
179     XSetWindowAttributes xswa;
180     unsigned int xswamask;
181     unsigned char *pchImageName = NULL;
182     unsigned char *pchL = NULL;
183     unsigned char *pch, *pLine;
184     Pixmap tmpPix;
185     int x, y;
186     unsigned int w, h, bw, depth;
187     Window root;
188     unsigned long oldFlags;
189     static String none_string = NULL;
190     static String no_backdrop_string = NULL;
191     Boolean bNone = False;
192     unsigned int chlen;
193     
194     if (callFlags & CHANGE_BACKDROP)
195     {
196         oldFlags = pWS->backdrop.flags;
197     }
198
199     if (!no_backdrop_string && 
200         (no_backdrop_string = XtNewString (DTWM_REQP_BACKDROP_NONE)))
201     {
202         ToLower(no_backdrop_string);
203         xa_NO_BACKDROP = XmInternAtom (DISPLAY, no_backdrop_string, False);
204
205         /* for compatiblity with DT 2.01 */
206         none_string = XtNewString ("none");
207     }
208     if (!no_backdrop_string)
209     {
210         Warning(((char *)GETMESSAGE(6, 4, "Insufficient memory for backdrop window.")));
211         return;
212     }
213
214     pWS->backdrop.flags = BACKDROP_NONE;        /* by default */
215
216     /*
217      *  see if we're using a bitmap 
218      */
219     if (pWS->backdrop.image)
220     {
221         /*
222          * Strip off leading '@', if any
223          */
224         pch = (unsigned char *) pWS->backdrop.image;
225         chlen = mblen ((char *)pch, MB_CUR_MAX);
226         if (chlen == 1 && *pch++ == '@')
227         {
228             chlen = mblen ((char *)pch, MB_CUR_MAX);
229             if (chlen >= 1)
230             {
231                 int j;
232                 int il = 1+strlen ((char *)pch);
233                 unsigned char *pchD = (unsigned char *)pWS->backdrop.image;
234
235                 while (il)
236                 {
237                     *pchD++ = *pch++;
238                     il--;
239                 }
240             }
241         }
242
243         /*
244          * Use a copy of the string because our parsing routines
245          * destroy the thing being parsed. 
246          */
247
248         if ((pLine = pchImageName = (unsigned char *) 
249                             strdup (pWS->backdrop.image)) &&
250             (pch = GetString(&pLine)))
251         {
252             pchL = (unsigned char *) strdup ((char *)pch);
253
254             if (*pchL) 
255                 ToLower((char *)pchL);
256         
257             if (!(strcmp ((char *)pchL, (char *)no_backdrop_string)) ||
258                 !(strcmp ((char *)pchL, (char *)none_string)))
259             {
260                 /*
261                  * No backdrop (root window shows through)
262                  */
263                 pWS->backdrop.window = None;
264                 pWS->backdrop.nameAtom = xa_NO_BACKDROP;
265                 bNone = True;
266             }
267
268             if (pch && !bNone)
269             {
270                 /*
271                  * Bitmap backdrop 
272                  * Load in the bitmap, create a pixmap of
273                  * the right depth, and make the backdrop
274                  * window if necessary.
275                  */
276                 if ((callFlags & CHANGE_BACKDROP))
277                 {
278                     GC gc;
279                     Display *display;
280                     Window win;
281                     int status, x, y;
282                     unsigned int bw, depth, h, w, junk;
283
284                     /*
285                      * We're changing the backdrop, so the
286                      * imagePixmap actually contains a depth 1
287                      * pixmap. Convert it into a pixmap of the
288                      * proper depth.
289                      */
290                     tmpPix = pWS->backdrop.imagePixmap;
291                     if (XmUNSPECIFIED_PIXMAP != tmpPix)
292                     {
293                         display = XtDisplay(pWS->workspaceTopLevelW);
294                         XGetGeometry(
295                             display, tmpPix,
296                             &win, &x, &y, &w, &h, &bw, &depth);
297                         pWS->backdrop.imagePixmap =
298                           XCreatePixmap(display, tmpPix, w, h, depth);
299                         gc = XCreateGC(display, tmpPix, 0, NULL);
300                         status = XCopyArea(
301                                 XtDisplay(pWS->workspaceTopLevelW),
302                                 tmpPix, pWS->backdrop.imagePixmap, gc,
303                                 0, 0, w, h, 0, 0);
304                         XFreeGC(display, gc);
305                     }
306
307                     if (XmUNSPECIFIED_PIXMAP == tmpPix || BadDrawable == status)
308                       pWS->backdrop.imagePixmap = 
309                         WmXmGetPixmap2 (XtScreen(pWS->workspaceTopLevelW),
310                                  (char *)pch,
311                                  pWS->backdrop.foreground,
312                                  pWS->backdrop.background);
313                 }
314                 else 
315                 {
316                     pWS->backdrop.imagePixmap =
317                         WmXmGetPixmap2 (XtScreen(pWS->workspaceTopLevelW),
318                                  (char *)pch,
319                                  pWS->backdrop.foreground,
320                                  pWS->backdrop.background);
321                 }
322
323                 if ((callFlags & CHANGE_BACKDROP) &&
324                     (pWS->backdrop.window))
325                 {
326                     if (pWS->backdrop.imagePixmap !=
327                             XmUNSPECIFIED_PIXMAP)
328                     {
329                         XSetWindowBackgroundPixmap (DISPLAY,
330                             pWS->backdrop.window,
331                             pWS->backdrop.imagePixmap);
332                     }
333                     else
334                     {
335                         /*
336                          * Failed to find bitmap
337                          * set background to "background"
338                          */
339                         XSetWindowBackground (DISPLAY, 
340                             pWS->backdrop.window, 
341                             pWS->backdrop.background);
342                     }
343                 }
344                 else
345                 {
346                     if (pWS->backdrop.imagePixmap !=
347                             XmUNSPECIFIED_PIXMAP)
348                     {
349                         xswa.override_redirect = True;    
350                         xswa.background_pixmap = 
351                             pWS->backdrop.imagePixmap; 
352                         xswamask = CWOverrideRedirect | CWBackPixmap;
353                     }
354                     else
355                     {
356                         xswa.override_redirect = True;    
357                         xswa.background_pixel = 
358                             pWS->backdrop.background; 
359                         xswamask = CWOverrideRedirect | CWBackPixel;
360                     }
361
362                     if ((wmGD.keyboardFocusPolicy == 
363                                         KEYBOARD_FOCUS_POINTER) ||
364                         (wmGD.colormapFocusPolicy == 
365                                         CMAP_FOCUS_POINTER))
366                     {
367                         /*
368                          * Listen for enter/levae events if we
369                          * have a pointer tracking focus policy
370                          */
371                         xswamask |= CWEventMask;
372                         xswa.event_mask = EnterWindowMask | 
373                                                 LeaveWindowMask;
374                     }
375
376                     xswa.backing_store = NotUseful;
377                     xswa.save_under = False;
378                     xswamask |= (CWBackingStore | CWSaveUnder);
379
380                     pWS->backdrop.window = XCreateWindow(DISPLAY, 
381                        pWS->pSD->rootWindow, 
382                        0, 0, 
383                        DisplayWidth(DISPLAY, pWS->pSD->screen), 
384                        DisplayHeight(DISPLAY, pWS->pSD->screen),
385                        0, 
386                        XDefaultDepth(DISPLAY,pWS->pSD->screen), 
387                        CopyFromParent,
388                        CopyFromParent, 
389                        xswamask, 
390                        &xswa);
391
392                 }
393
394                 if (pch &&
395                     (pWS->backdrop.imagePixmap != XmUNSPECIFIED_PIXMAP) &&
396                     (pWS->backdrop.window))
397                 {
398                     /* 
399                      * Succeeded in setting up a bitmap backdrop.
400                      */
401                     pWS->backdrop.flags |= BACKDROP_BITMAP;
402
403                     pWS->backdrop.nameAtom = XmInternAtom (DISPLAY, 
404                                             pWS->backdrop.image, False);
405                 }
406                 else
407                 {
408                     char msg[MAXWMPATH+1];
409
410                     sprintf ((char *)msg, 
411                         ((char *)GETMESSAGE(6, 3, "Unable to get image %s for workspace %s.")),
412                         pWS->backdrop.image, pWS->name);
413
414                     Warning(msg);
415                 }
416                 pch = NULL;
417             }
418             free (pchImageName);        /* temporary string */
419             pchImageName = NULL;
420             free (pchL);        /* temporary string */
421         }
422     }
423
424     free (pchImageName);
425 }
426
427 \f
428 /******************************<->*************************************
429  *
430  *  static Pixmap WmXmGetPixmap2 
431  *
432  *  Description:
433  *  -----------
434  *  Tries twice to get a pixmap from a file name
435  *
436  *  Inputs:
437  *  ------
438  *  screen      - ptr to screen
439  *  pchName     - image file name
440  *  fg          - foreground color
441  *  bg          - background color
442  * 
443  *  Outputs:
444  *  -------
445  *  Return      -  pixmap if found, XmUNSPECIFIED_PIXMAP if not
446  *
447  *  Comments:
448  *  ---------
449  *  This routine performs some backward compatibility checks.
450  *
451  *  Do a two stage lookup for backdrop files. If a full path
452  *  is specified, but XmGetPixmap fails, the get the basename
453  *  of the file and try again. 
454  *
455  *************************************<->***********************************/
456 static Pixmap 
457 WmXmGetPixmap2 (
458         Screen          *screen,
459         char            *pchName,
460         Pixel           fg,
461         Pixel           bg)
462 {
463     Pixmap pixReturn;
464     char *pch;
465
466     if (pchName && *pchName) 
467     {
468         pixReturn = XmGetPixmap (screen, pchName, fg, bg);
469
470         if (pixReturn == XmUNSPECIFIED_PIXMAP)
471         {
472             /* 
473              * Use our bitmap lookup paths by using only the 
474              * basename of the file path.
475              */
476             pch = strrchr (pchName, '/');
477             if (pch && 
478                 (pch < (pchName + strlen(pchName) - 1)))
479             {
480                 pch++;
481                 pixReturn = XmGetPixmap (screen, pch, fg, bg);
482             }
483         }
484     }
485     else
486     {
487         pixReturn = XmUNSPECIFIED_PIXMAP;
488     }
489
490     return (pixReturn);
491 }
492
493
494 \f
495 /******************************<->*************************************
496  *
497  *  FullBitmapFilePath (pch)
498  *
499  *  Description:
500  *  -----------
501  *  Takes a bitmap file name turns it into a full path name.
502  *
503  *  Inputs:
504  *  ------
505  *  pch = ptr to bitmap file name
506  * 
507  *  Outputs:
508  *  -------
509  *  Return = ptr to a string containing full path name
510  *           or NULL on failure
511  *
512  *  Comments:
513  *  ---------
514  *
515  *************************************<->***********************************/
516 String 
517 FullBitmapFilePath(
518         String pch )
519 {
520     String pchR;
521     struct stat buf;
522
523     if (*pch != '/')
524     {
525         pchR = (String) BitmapPathName (pch);
526
527         if ((stat(pchR, &buf) == -1) &&
528             (*pch != '~'))
529         {
530             /* file not there! */
531             pchR = pch;
532         }
533     }
534     else
535     {
536         pchR = pch;
537     }
538     return (pchR);
539 }
540
541 \f
542 /******************************<->*************************************
543  *
544  *  SetNewBackdrop (pWS, pixmap, aName)
545  *
546  *  Description:
547  *  -----------
548  *  Sets a new backdrop for a workspace
549  *
550  *  Inputs:
551  *  ------
552  *  pWS = pointer to workspace data
553  *  pixmap = pixmap for the backdrop (if any)
554  *  aName = atomized name for the backdrop (either file name or "none")
555  * 
556  *  Outputs:
557  *  -------
558  *  Return = ptr to a string containing full path name
559  *           or NULL on failure
560  *
561  *  Comments:
562  *  ---------
563  *
564  *************************************<->***********************************/
565 void 
566 SetNewBackdrop(
567         WmWorkspaceData *pWS,
568         Pixmap pixmap,
569         String bitmapFile )
570 {
571     String pchNewBitmap = NULL;
572
573     if (!bitmapFile || !strlen(bitmapFile) || 
574         !strcmp(bitmapFile, DTWM_REQP_BACKDROP_NONE))
575     {
576         pixmap = None;
577     }
578
579     if (bitmapFile) 
580     {
581         pchNewBitmap = (String) XtNewString (bitmapFile);
582     }
583
584     /*
585      * Free up old resources 
586      */
587     if ((pWS->backdrop.imagePixmap) &&
588         (pWS->backdrop.imagePixmap != pixmap))
589     {
590         if (!XmDestroyPixmap (XtScreen(pWS->workspaceTopLevelW), 
591                         pWS->backdrop.imagePixmap))
592         {
593             /* not in Xm pixmap cache */
594         }
595         pWS->backdrop.imagePixmap = None;
596     }
597
598     /* free pWS->backdrop.image */
599     if ((pWS->backdrop.flags & BACKDROP_IMAGE_ALLOCED) &&
600         (pWS->backdrop.image))
601     {
602         free (pWS->backdrop.image);
603     }
604         
605     pWS->backdrop.imagePixmap = pixmap;
606     pWS->backdrop.image = pchNewBitmap;
607
608     ProcessBackdropResources (pWS, CHANGE_BACKDROP);
609
610     if (pchNewBitmap)
611     {
612         pWS->backdrop.flags |= BACKDROP_IMAGE_ALLOCED;
613     }
614
615     ChangeBackdrop (pWS);
616     SaveWorkspaceResources (pWS, WM_RES_BACKDROP_IMAGE);
617
618 #ifdef HP_VUE
619     UpdateWorkspaceInfoProperty (pWS->pSD); /* to be backward compatible */
620 #endif /* HP_VUE */
621     SetWorkspaceInfoProperty (pWS);
622
623     /*
624      * Inform the world of the new workspace title
625      */
626     dtSendWorkspaceModifyNotification(pWS->pSD, pWS->id, 
627                                                 DtWSM_REASON_BACKDROP);
628 }
629
630 \f
631 /******************************<->*************************************
632  *
633  *  Boolean IsBackdropWindow (pSD, win)
634  *
635  *  Description:
636  *  -----------
637  *  Tests a window to see if it is a backdrop window
638  *
639  *  Inputs:
640  *  ------
641  *  pSD = pointer to screen data
642  *  win = window to test.
643  * 
644  *  Outputs:
645  *  -------
646  *  Return = True if win is a backdrop window.
647  *           False otherwise.
648  *
649  *  Comments:
650  *  ---------
651  *
652  *************************************<->***********************************/
653 Boolean 
654 IsBackdropWindow(
655         WmScreenData *pSD,
656         Window win )
657 {
658     Boolean rval = False;
659     int i;
660
661     /*
662      * Is it one of the backdrop windows for a workspace?
663      */
664     for (i=0; (i < pSD->numWorkspaces) && !rval; i++)
665     {
666         if (pSD->pWS[i].backdrop.window == win)
667         {
668             rval = True;
669         }
670     }
671
672     return (rval);
673 }
674
675 /*********************        eof     ***************************/