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