Add GNU LGPL headers to all .c .C and .h files
[oweals/cde.git] / cde / examples / dtdnd / icon.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 /* $XConsortium: icon.c /main/3 1995/10/27 10:39:09 rswiston $ */
24 /*****************************************************************************
25  *****************************************************************************
26  **
27  **   File:         icon.c
28  **
29  **   Description:  Icon support functions for the CDE Drag & Drop Demo.
30  **
31  **  (c) Copyright 1993, 1994 Hewlett-Packard Company
32  **  (c) Copyright 1993, 1994 International Business Machines Corp.
33  **  (c) Copyright 1993, 1994 Sun Microsystems, Inc.
34  **  (c) Copyright 1993, 1994 Unix System Labs, Inc., a subsidiary of
35  **      Novell, Inc.
36  **
37  ****************************************************************************
38  ************************************<+>*************************************/
39
40 #include <stdio.h>
41
42 #include <Xm/Screen.h>
43
44 #include <Dt/Dts.h>
45 #include <Dt/Dnd.h>
46
47 #include "icon.h"
48
49  /*************************************************************************
50  *
51  *       Data Structures & Private Declarations For Icon Handling Functions
52  *
53  **************************************************************************/
54
55 #define ICON_TEXT_YGAP  2
56
57 #define ICON_PATH               "/usr/dt/appconfig/icons/C"
58 #define ICON_BITMAP_SUFFIX      "m.bm"
59 #define ICON_MASK_SUFFIX        "m_m.bm"
60
61 /*
62  * Default Generic Icon Bitmap & Mask
63  */
64
65 #define iconWidth 32
66 #define iconHeight 32
67 static unsigned char iconBits[] = {
68    0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0x0f, 0x08, 0x00, 0x00, 0x08,
69    0x08, 0x00, 0x00, 0x08, 0x08, 0x00, 0x00, 0x08, 0x88, 0x9d, 0x6d, 0x08,
70    0x08, 0x00, 0x00, 0x08, 0x08, 0x00, 0x00, 0x08, 0x88, 0xf9, 0xed, 0x08,
71    0x08, 0x00, 0x00, 0x08, 0xc8, 0x6e, 0x7d, 0x08, 0x08, 0x00, 0x00, 0x08,
72    0xc8, 0x9d, 0xef, 0x09, 0x08, 0x00, 0x00, 0x08, 0xc8, 0xdd, 0xb3, 0x08,
73    0x08, 0x00, 0x00, 0x08, 0xc8, 0xdf, 0xfd, 0x09, 0x08, 0x00, 0x00, 0x08,
74    0xc8, 0xf6, 0xde, 0x08, 0x08, 0x00, 0x00, 0x08, 0x08, 0x00, 0x00, 0x08,
75    0x88, 0xed, 0xd2, 0x08, 0x08, 0x00, 0x00, 0x08, 0xc8, 0xbb, 0xf3, 0x08,
76    0x08, 0x00, 0x00, 0x08, 0x48, 0xdf, 0x5e, 0x08, 0x08, 0x00, 0x00, 0x08,
77    0xc8, 0x36, 0x00, 0x08, 0x08, 0x00, 0x00, 0x08, 0x08, 0x00, 0x00, 0x08,
78    0x08, 0x00, 0x00, 0x08, 0xf8, 0xff, 0xff, 0x0f};
79  
80 #define iconMaskWidth 32
81 #define iconMaskHeight 32
82 static unsigned char iconMaskBits[] = {
83    0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0x0f, 0xf8, 0xff, 0xff, 0x0f,
84    0xf8, 0xff, 0xff, 0x0f, 0xf8, 0xff, 0xff, 0x0f, 0xf8, 0xff, 0xff, 0x0f,
85    0xf8, 0xff, 0xff, 0x0f, 0xf8, 0xff, 0xff, 0x0f, 0xf8, 0xff, 0xff, 0x0f,
86    0xf8, 0xff, 0xff, 0x0f, 0xf8, 0xff, 0xff, 0x0f, 0xf8, 0xff, 0xff, 0x0f,
87    0xf8, 0xff, 0xff, 0x0f, 0xf8, 0xff, 0xff, 0x0f, 0xf8, 0xff, 0xff, 0x0f,
88    0xf8, 0xff, 0xff, 0x0f, 0xf8, 0xff, 0xff, 0x0f, 0xf8, 0xff, 0xff, 0x0f,
89    0xf8, 0xff, 0xff, 0x0f, 0xf8, 0xff, 0xff, 0x0f, 0xf8, 0xff, 0xff, 0x0f,
90    0xf8, 0xff, 0xff, 0x0f, 0xf8, 0xff, 0xff, 0x0f, 0xf8, 0xff, 0xff, 0x0f,
91    0xf8, 0xff, 0xff, 0x0f, 0xf8, 0xff, 0xff, 0x0f, 0xf8, 0xff, 0xff, 0x0f,
92    0xf8, 0xff, 0xff, 0x0f, 0xf8, 0xff, 0xff, 0x0f, 0xf8, 0xff, 0xff, 0x0f,
93    0xf8, 0xff, 0xff, 0x0f, 0xf8, 0xff, 0xff, 0x0f};
94  
95 /*
96  * Blank Bitmap
97  */
98
99 #define blankWidth 16
100 #define blankHeight 16
101 static unsigned char blankBits[] = {
102    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
103    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
104    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
105 };
106
107 /*
108  * Private Icon Handling Function Declarations
109  */
110
111 static void     iconClearBitmap(Display*, Window, GC, Pixmap, int, int);
112 static Pixmap   iconDefaultBitmap(Display*, Window, IconBitmapPart,
113                         unsigned short*, unsigned short*);
114 static void     iconFree(IconInfo*);
115 static Pixmap   iconGetBitmap(Widget, char*, IconBitmapPart, unsigned short*,
116                         unsigned short*);
117 static char     *iconGetIconPath(void*, int, IconTyping, IconBitmapPart);
118 static Pixmap   iconMergeBitmaps(Widget, Pixmap, int, int, Pixmap, int, int,
119                         int, int, Boolean);
120
121  /*************************************************************************
122  *
123  *      Public Icon Handling Functions
124  *
125  **************************************************************************/
126
127 /*
128  * IconCreateDouble
129  *
130  * Create a double icon from a single icon. The double icon has a bitmap
131  * consisting of 2 images of the original bitmap offset from one another.
132  */
133 void
134 IconCreateDouble(
135         Widget          widget,
136         IconInfo        *oldIcon,
137         int             xOffset,
138         int             yOffset,
139         IconInfo        *newIcon,
140         short           xx,
141         short           yy)
142 {
143         newIcon->bitmap = iconMergeBitmaps(widget,
144                 oldIcon->bitmap, oldIcon->icon.width, oldIcon->icon.height,
145                 oldIcon->bitmap, oldIcon->icon.width, oldIcon->icon.height,
146                 xOffset, yOffset, False);
147         newIcon->mask = iconMergeBitmaps(widget,
148                 oldIcon->mask, oldIcon->icon.width, oldIcon->icon.height,
149                 oldIcon->mask, oldIcon->icon.width, oldIcon->icon.height,
150                 xOffset, yOffset, True);
151         newIcon->icon.width = oldIcon->icon.width + 10;
152         newIcon->icon.height = oldIcon->icon.height + 10;
153         newIcon->name = XtNewString("Multiple");
154         newIcon->icon.x = xx;
155         newIcon->icon.y = yy;
156         newIcon->dragIcon = DtDndCreateSourceIcon(widget,
157                 newIcon->bitmap, newIcon->mask);
158 }
159
160 /*
161  * IconDelete
162  *
163  * Remove the icon from its list and deallocate memory used by the icon.
164  */
165 void
166 IconDelete(
167         Widget          drawArea,
168         IconInfo        *iconPtr)
169 {
170         IconInfo        *iconList;
171
172         if (iconPtr == NULL || drawArea == NULL) {
173                 return;
174         }
175
176         if (iconPtr->next != NULL) { /* iconPtr is not the tail of the list */
177                 iconPtr->next->prev = iconPtr->prev;
178         }
179
180         if (iconPtr->prev != NULL) { /* iconPtr is not the head of the list */
181                 iconPtr->prev->next = iconPtr->next;
182         }
183         if (iconPtr->next == NULL) { /* iconPtr is the tail of the list */
184                 iconList = iconPtr->prev;
185         } else {
186                 iconList = iconPtr->next;
187         }
188
189         while (iconList != NULL && iconList->prev != NULL) {
190                 iconList = iconList->prev;
191         }
192         iconFree(iconPtr);
193
194         XtVaSetValues(drawArea, XmNuserData, iconList, NULL);
195 }
196
197 /*
198  * IconDraw
199  *
200  * Render given icon in the window of the given widget.
201  */
202 void
203 IconDraw(
204         Widget          widget,
205         IconInfo        *iconPtr)
206 {
207         static GC       graphicsContext = NULL;
208         static XFontStruct *fontStruct;
209         Display         *display = XtDisplayOfObject(widget);
210         Window          window = XtWindow(widget);
211         int             screen = DefaultScreen(display);
212         XGCValues       gcValues;
213
214         if (graphicsContext == NULL) {
215                 gcValues.foreground = BlackPixel(display, screen);
216                 gcValues.background = WhitePixel(display, screen);
217                 graphicsContext = XCreateGC(display, window,
218                                 GCForeground | GCBackground, &gcValues);
219         }
220
221         /*
222          * Draw icon
223          */
224
225         gcValues.clip_mask = iconPtr->mask;
226         gcValues.clip_x_origin = iconPtr->icon.x;
227         gcValues.clip_y_origin = iconPtr->icon.y;
228         XChangeGC(display, graphicsContext,
229                 GCClipMask | GCClipXOrigin | GCClipYOrigin, &gcValues);
230         XCopyPlane(display, iconPtr->bitmap, window, graphicsContext, 0, 0,
231                 iconPtr->icon.width, iconPtr->icon.height,
232                 iconPtr->icon.x, iconPtr->icon.y, 1L);
233
234         /*
235          * Draw icon name centered below icon
236          */
237
238         if (iconPtr->name != NULL) {
239                 int             nameX, nameY;
240                 int             direction, ascent, decent;
241                 XCharStruct     overall;
242                 Widget          xmScreen;
243  
244                 if (fontStruct == NULL) {
245                         xmScreen = XmGetXmScreen(XtScreen(widget));
246                         XtVaGetValues(xmScreen, XmNfont, &fontStruct, NULL);
247                 }
248                 XTextExtents(fontStruct, iconPtr->name, strlen(iconPtr->name),
249                         &direction, &ascent, &decent, &overall);
250  
251                 nameX = (iconPtr->icon.x + (iconPtr->icon.width/2)) -
252                         (overall.width/2);
253                 nameY = iconPtr->icon.y + iconPtr->icon.height +
254                         ICON_TEXT_YGAP + ascent;
255  
256                 gcValues.font = fontStruct->fid;
257                 gcValues.clip_mask = None;
258                 XChangeGC(display, graphicsContext,
259                         GCFont | GCClipMask, &gcValues);
260                 XDrawString(display, window, graphicsContext, nameX, nameY,
261                         iconPtr->name, strlen(iconPtr->name));
262         }
263 }
264
265 /*
266  * IconInitialize
267  *
268  * Initialize given icon with given data. Get icon bitmap based on data
269  * associated with the icon. This data may be a file name, a buffer or
270  * a type name. Create source icon for dragging based on the bitmap and mask.
271  */
272 void
273 IconInitialize(
274         Widget          widget,
275         IconInfo        *iconPtr,
276         short           x,
277         short           y,
278         void            *data,
279         int             dataLen,
280         char            *name,
281         IconTyping      typing)
282 {
283         char            *iconPath;
284
285         iconPath = iconGetIconPath(data, dataLen, typing, IconMask);
286         iconPtr->mask = iconGetBitmap(widget, iconPath, IconMask,
287                 &(iconPtr->icon.width), &(iconPtr->icon.height));
288         XtFree(iconPath);
289
290         iconPath = iconGetIconPath(data, dataLen, typing, IconBitmap);
291         iconPtr->bitmap = iconGetBitmap(widget, iconPath, IconBitmap,
292                 &(iconPtr->icon.width), &(iconPtr->icon.height));
293         XtFree(iconPath);
294
295         iconPtr->icon.x = x;
296         iconPtr->icon.y = y;
297         iconPtr->name = XtNewString(name);
298         iconPtr->dragIcon = DtDndCreateSourceIcon(widget, 
299                 iconPtr->bitmap, iconPtr->mask); 
300 }
301
302 /*
303  * IconNew
304  *
305  * Allocate memory for a new icon structure and clear.
306  */
307 IconInfo*
308 IconNew()
309 {
310         IconInfo        *iconPtr;
311
312         iconPtr = (IconInfo*) XtMalloc(sizeof(IconInfo));
313         memset(iconPtr, 0x00, sizeof(IconInfo));
314
315         return iconPtr;
316 }
317
318  /*************************************************************************
319  *
320  *      Private Icon Handling Functions
321  *
322  **************************************************************************/
323
324 /*
325  * iconClearBitmap
326  *
327  * Clear a bitmap by filling it with zeros.
328  */
329 static void
330 iconClearBitmap(
331         Display         *display,
332         Window          window,
333         GC              graphicsContext,
334         Pixmap          bitmap,
335         int             width,
336         int             height)
337 {
338         int             xx, yy;
339         static Pixmap   blankBitmap = NULL;
340
341         if (blankBitmap == NULL) {
342                 blankBitmap = XCreateBitmapFromData(display, window,
343                         (char *)blankBits, blankWidth, blankHeight);
344         }
345         for (xx = 0; xx < width + blankWidth; xx += blankWidth) {
346                 for (yy = 0; yy < height + blankHeight; yy += blankHeight) {
347                         XCopyArea(display, blankBitmap, bitmap,
348                                 graphicsContext, 0, 0,
349                                 blankWidth, blankHeight, xx, yy);
350                 }
351         }
352 }
353
354 /*
355  * iconDefaultBitmap
356  *
357  * Create default icon bitmap or mask and set width and height accordingly.
358  */
359 static Pixmap
360 iconDefaultBitmap(
361         Display         *display,
362         Window          window,
363         IconBitmapPart  iconPart,
364         unsigned short  *width,
365         unsigned short  *height)
366 {
367         static Pixmap   bitmap;
368         static Pixmap   mask;
369
370         if (iconPart == IconMask) { /* create default mask */
371                 if (mask == NULL) {
372                         mask = XCreateBitmapFromData(display, window,
373                            (char *)iconMaskBits, iconMaskWidth, iconMaskHeight);
374                 }
375                 *width = iconMaskWidth;
376                 *height = iconMaskHeight;
377
378                 return mask;
379
380         } else { /* create default bitmap */
381                 if (bitmap == NULL) {
382                         bitmap = XCreateBitmapFromData(display, window,
383                                 (char *)iconBits, iconWidth, iconHeight);
384                 }
385                 *width = iconWidth;
386                 *height = iconHeight;
387
388                 return bitmap;
389         }
390 }
391
392 /*
393  * iconFree
394  *
395  * Deallocate the icon and associated resources.
396  */
397 static void
398 iconFree(
399         IconInfo        *iconPtr)
400 {
401         Display         *display = XtDisplayOfObject(iconPtr->dragIcon);
402
403         if (iconPtr == NULL) {
404                 return;
405         }
406
407         XtFree(iconPtr->name);
408         /*
409          * REMIND: This needs to free other things too...
410          * XFreePixmap(display, iconPtr->bitmap);
411          * XFreePixmap(display, iconPtr->mask);
412          * Free(iconPtr->dragIcon);
413          */
414         XtFree((char *)iconPtr);
415 }
416
417 /*
418  * iconGetBitmap
419  *
420  * Get a bitmap for the icon based on the path and name of the icon. 
421  * If no bitmap file is found use a built-in default.
422  */
423 static Pixmap
424 iconGetBitmap(
425         Widget          widget,
426         char            *iconPath,
427         IconBitmapPart  iconPart,
428         unsigned short  *returnWidth,
429         unsigned short  *returnHeight)
430 {
431         Display         *display = XtDisplayOfObject(widget);
432         Window          window = DefaultRootWindow(display);
433         int             status;
434         int             xHot, yHot;
435         Pixmap          bitmap;
436         unsigned int    width, height;
437         
438         *returnWidth = *returnHeight = 0;
439
440         if (iconPath != NULL) {
441
442                 status = XReadBitmapFile(display, window, iconPath,
443                         &width, &height, &bitmap, &xHot, &yHot);
444
445                 if (status == BitmapSuccess) {
446                         *returnWidth = (unsigned short) width;
447                         *returnHeight = (unsigned short) height;
448                 } else {
449                         printf(
450                             "Unable to read icon from bitmap file \"%s\".\n"
451                             "Using default icon bitmap.\n",
452                             iconPath, NULL);
453                         bitmap = iconDefaultBitmap(display, window, iconPart,
454                                 returnWidth, returnHeight);
455                 }
456         } else {
457                 bitmap = iconDefaultBitmap(display, window, iconPart,
458                         returnWidth, returnHeight);
459         }
460         return bitmap;
461 }
462
463 /*
464  * iconGetIconPath
465  *
466  * Get the file path and name for an icon based on the given data and
467  * method of typing that data. This function assumes the data typing
468  * database has been loaded with DtDtsLoadDataTypes().
469  */
470 static char*
471 iconGetIconPath(
472         void            *data,
473         int             dataLen,
474         IconTyping      typing,
475         IconBitmapPart  iconPart)
476 {
477         char            iconPath[MAXPATHLEN + 1],
478                         *iconName,
479                         *iconSuffix;
480
481         switch (typing) {
482         case IconByFile:
483                 iconName = DtDtsFileToAttributeValue(data, "ICON");
484                 break;
485         case IconByData:
486                 iconName = DtDtsBufferToAttributeValue(data, dataLen,
487                         "ICON", NULL);
488                 break;
489         case IconByType:
490                 iconName = DtDtsDataTypeToAttributeValue(data, "ICON", NULL);
491                 break;
492         default:
493                 iconName = NULL;
494         }
495         if (iconName != NULL) {
496                 if (iconPart == IconMask) {
497                         iconSuffix = ICON_MASK_SUFFIX;
498                 } else {
499                         iconSuffix = ICON_BITMAP_SUFFIX;
500                 }
501                 sprintf(iconPath, "%s/%s.%s", ICON_PATH, iconName, iconSuffix);
502                 DtDtsFreeAttributeValue(iconName);
503         }
504         return XtNewString(iconPath);
505 }
506
507 /*
508  * iconMergeBitmaps
509  *
510  * Create new bitmap consisting of the offset composition of the given bitmaps.
511  */
512 static Pixmap
513 iconMergeBitmaps(
514         Widget          widget,
515         Pixmap          bitmap1,
516         int             width1,
517         int             height1,
518         Pixmap          bitmap2,
519         int             width2,
520         int             height2,
521         int             xOffset,
522         int             yOffset,
523         Boolean         clear)
524 {
525         Display         *display = XtDisplayOfObject(widget);
526         Window          window = DefaultRootWindow(display);
527         int             screen = DefaultScreen(display);
528         Pixmap          mergedBitmap, blankBitmap;
529         int             extraX, extraY, width, height;
530         static GC       graphicsContext = NULL;
531         XGCValues       gcValues;
532
533         extraX = width2 - width1 + xOffset + 1;
534         if (extraX < 0) extraX = 0;
535         width = width1 + extraX;
536
537         extraY = height2 - height1 + yOffset + 1;
538         if (extraY < 0) extraY = 0;
539         height = height1 + extraY;
540
541         mergedBitmap = XCreatePixmap(display, window, width, height, 1);
542
543         if (graphicsContext == NULL) {
544                 graphicsContext = XCreateGC(display, mergedBitmap, 0L, NULL);
545         }
546
547         if (clear) {
548                 iconClearBitmap(display, window, graphicsContext, mergedBitmap,
549                         width, height);
550         }
551
552         XCopyArea(display, bitmap2, mergedBitmap, graphicsContext, 0, 0,
553                 width2, height2, xOffset, yOffset);
554
555         XCopyArea(display, bitmap1, mergedBitmap, graphicsContext, 0, 0,
556                 width1, height1, 0, 0);
557
558         return mergedBitmap;
559 }
560