Add GNU LGPL headers to all .c .C and .h files
[oweals/cde.git] / cde / programs / dtappbuilder / src / ab / pal_create.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
24 /*
25  *      $XConsortium: pal_create.c /main/4 1996/07/25 09:19:49 mustafa $
26  *
27  *      @(#)pal_create.c        1.102 19 May 1995
28  *
29  *      RESTRICTED CONFIDENTIAL INFORMATION:
30  *
31  *      The information in this document is subject to special
32  *      restrictions in a confidential disclosure agreement between
33  *      HP, IBM, Sun, USL, SCO and Univel.  Do not distribute this
34  *      document outside HP, IBM, Sun, USL, SCO, or Univel without
35  *      Sun's specific written approval.  This document and all copies
36  *      and derivative works thereof must be returned or destroyed at
37  *      Sun's request.
38  *
39  *      Copyright 1993 Sun Microsystems, Inc.  All rights reserved.
40  *
41  */
42
43
44 /*
45  ***********************************************************************
46  * pal_create.c - Implements object creation (dragging & dropping items
47  *               off the palette)
48  *
49  ***********************************************************************
50  */
51 #include <stdio.h>
52 #include <X11/Intrinsic.h>
53 #include <Xm/Xm.h>
54 #include <Xm/BulletinB.h>
55 #include <Xm/CascadeB.h>
56 #include <Xm/Form.h>
57 #include <Xm/Label.h>
58 #include <Xm/TextF.h>
59 #include <Xm/ToggleB.h>
60 #include <Xm/SelectioB.h>
61 #include <Xm/Scale.h>
62 #include <Dt/SpinBox.h>
63 #include <Dt/ComboBox.h>
64 #include <ab_private/trav.h>
65 #include <ab_private/objxm.h>
66 #include <ab_private/brws.h>
67 #include <ab_private/proj.h>
68 #include <ab_private/abobj.h>
69 #include <ab_private/abobj_set.h>
70 #include <ab_private/abobj_edit.h>
71 #include <ab_private/ab.h>
72 #include <ab_private/pal.h>
73 #include <ab_private/prop.h>
74 #include <ab_private/ui_util.h>
75 #include <ab_private/x_util.h>
76 #include "dtbuilder.h"
77 #include "palette_ui.h"
78
79 const int AB_max_item_height = 64;
80 const int AB_max_item_width  = 256;
81
82 /*
83  * Default (x,y) positions of objects when dragged out
84  * from palette. This is only used when the objects are not
85  * dropped onto the interface created, but dropped instead 
86  * onto the browser.
87  */
88 #define AB_DEFAULT_X    0
89 #define AB_DEFAULT_Y    0
90
91 /*************************************************************************
92 **                                                                      **
93 **       Private Function Declarations                                  **
94 **                                                                      **
95 **************************************************************************/
96 static void     palitem_update_type(
97                     Widget w,
98                     XtPointer cd,
99                     XEvent *ev,
100                     Boolean *cont
101                 );
102 static void     palitem_select_event( 
103                     Widget w, 
104                     XtPointer cd, 
105                     XEvent *ev, 
106                     Boolean *cont
107                 );
108 static  void    palitem_drag_action( 
109                     Widget w, 
110                     int    subtype,
111                     XEvent *event 
112                 );
113 static void     palitem_release_event(
114                     Widget w, 
115                     XtPointer cd, 
116                     XEvent *ev, 
117                     Boolean *cont
118                 );
119 static void     create_obj_action(
120                     Widget w, 
121                     int    subtype,
122                     XEvent *event
123                 );
124 static char     *locate_obj_parent(
125                     ABObj obj, 
126                     Widget widget, 
127                     int x, 
128                     int y,
129                     ABObj *parentptr,
130                     BOOL  *ModuleCreated
131                 );
132 static Boolean  initiate_drag(
133                     Widget w, 
134                     int    subtype,
135                     int *x, 
136                     int *y, 
137                     int *xhot, 
138                     int *yhot
139                 );
140 static XImage   *build_item_image(
141                     Widget w
142                 );
143 static void     image_copy(
144                     Widget w, 
145                     XImage *from, 
146                     XImage *to, 
147                     int width, 
148                     int gx, 
149                     int px
150                 );
151 ABObj           locate_obj_at_rootxy(
152                     int     x,
153                     int     y,
154                     int     *p_wx,
155                     int     *p_wy
156                 );
157
158
159 /*************************************************************************
160 **                                                                      **
161 **       Private Data                                                   **
162 **                                                                      **
163 **************************************************************************/
164 static Widget   palette_widget = NULL; 
165 static Cursor   drag_cursor;
166 static int      drag_cursor_xhot;
167 static int      drag_cursor_yhot;
168 static Boolean  drag_on = FALSE;
169
170 /*************************************************************************
171 **                                                                      **
172 **       Function Definitions                                           **
173 **                                                                      **
174 **************************************************************************/
175 /*
176  * Set up palette item(widget) to handle select-drag operation
177  */
178 void
179 pal_enable_item_drag(
180     Widget      widget,
181     int         subtype
182 )
183 {
184     static int st_subtype;
185
186     st_subtype = subtype;
187     XtInsertEventHandler(widget, ButtonPressMask, FALSE,
188             palitem_select_event, (XtPointer)&st_subtype, XtListHead);
189     XtInsertEventHandler(widget, ButtonReleaseMask, FALSE,
190             palitem_release_event, (XtPointer)&st_subtype, XtListHead);
191     XtAddEventHandler(widget, EnterWindowMask|LeaveWindowMask, FALSE,
192             palitem_update_type, (XtPointer)&st_subtype);
193
194     /* We need to keep track of the main palette widget
195      * for drag-behavior purposes
196      */
197     if (!palette_widget)
198     {
199         if ((palette_widget = dtb_palette_ab_palette_main.palette_cpanel) == NULL)
200         {
201             if (util_get_verbosity() > 2)
202                 fprintf(stderr,"pal_enable_item_drag: couldn't find \"%s\"\n",
203                         XtName(dtb_palette_ab_palette_main.palette_cpanel));
204             palette_widget = XtParent(XtParent(widget));
205         }
206     }
207 }
208 static void
209 palitem_update_type(
210     Widget       w,
211     XtPointer clientData,
212     XEvent       *event,
213     Boolean   *cont_dispatch
214 )
215 {
216     PalItemInfo   *palitem;
217     int           subtype = *((int*)clientData);
218     String        objname;
219     int           i;
220
221     XtVaGetValues(w, XmNuserData, &palitem, NULL);
222
223     if (event->type == EnterNotify)
224     {
225         objname = palitem->name;  
226
227         for(i=0; i < palitem->num_subinfo; i++)
228             if (palitem->subinfo[i].subtype == subtype)
229             {
230                 objname = palitem->subinfo[i].subname;
231                 break;
232             }
233                 
234         ab_update_stat_region(AB_STATUS_OBJ_TYPE, objname);
235     }
236     else /* LeaveNotify */
237         ab_update_stat_region(AB_STATUS_OBJ_TYPE, "     ");
238
239 }
240
241 /*
242  * EventHandler: ButtonPress activated on palette item
243  */
244 static void
245 palitem_select_event(
246     Widget       w, 
247     XtPointer clientData, 
248     XEvent       *event, 
249     Boolean   *cont_dispatch
250 )
251 {
252     XButtonEvent *bevent;
253     int          subtype = *((int*)clientData);
254
255     if (event->type != ButtonPress)
256         return;
257
258     bevent = (XButtonEvent*)event;
259     *cont_dispatch = FALSE;
260
261     if (AB_builder_mode != MODE_BUILD)
262         return;
263
264     if (bevent->button == 1 || 
265         (AB_btn1_transfer != True && bevent->button == 2))
266         palitem_drag_action(w, subtype, event);
267
268 }
269
270 /*
271  * Action Proc: Palette item has been selected - begin drag
272  */
273 static void
274 palitem_drag_action(
275     Widget     widget, 
276     int        subtype,
277     XEvent     *event 
278 )
279 {
280     int x, y;
281     Display *dpy = XtDisplay(widget);
282
283     if (event->type == ButtonPress)
284     {
285         XButtonEvent *bevent = (XButtonEvent*)event;
286  
287         x = bevent->x;
288         y = bevent->y;
289  
290         if (!initiate_drag(widget, subtype, &x, &y, &drag_cursor_xhot, &drag_cursor_yhot))
291         {
292             drag_on = FALSE;
293             if (util_get_verbosity() > 2)
294                 fprintf(stderr, "palitem_drag_action: couldn't begin drag\n");
295         }
296         else
297             drag_on = TRUE;
298     }
299
300 }
301
302 /*
303  * EventHandler: ButtonRelease activated on palette item
304  */
305 static void 
306 palitem_release_event(
307     Widget       w, 
308     XtPointer clientData, 
309     XEvent       *event, 
310     Boolean      *cont_dispatch
311
312 {
313     XButtonEvent *bevent;
314     int          subtype = *((int*)clientData);
315
316     if (event->type != ButtonRelease)
317         return;
318
319     bevent = (XButtonEvent*)event;
320     *cont_dispatch = FALSE;
321
322     if (AB_builder_mode != MODE_BUILD)
323         return;
324
325     if (bevent->button == 1 || 
326         (AB_btn1_transfer != True && bevent->button == 2))
327         create_obj_action(w, subtype, event);
328  
329
330
331
332 /*
333  * Action Proc: Palette item has been released; if drag was taking
334  *    place, release the pointer grab and create object
335  */
336 static void
337 create_obj_action(
338     Widget     widget, 
339     int        subtype,
340     XEvent     *event
341
342
343     ABObj         project = proj_get_project();
344     ABObj         obj = NULL;
345     ABObj         obj_parent = NULL;
346     PalItemInfo   *palitem;
347     Display       *dpy;
348     char          *errmsg = NULL;
349     BOOL          ModuleCreated = FALSE;
350     XmString      xm_buf = (XmString) NULL;
351
352     dpy = XtDisplay(widget);
353
354     if (drag_on)
355     {
356         XUngrabPointer(dpy, CurrentTime);
357         XFreeCursor(dpy, drag_cursor);
358         drag_on = FALSE;
359     }
360
361     if (event->type == ButtonRelease)
362     {
363         Window       xy_win;
364         int          wx, wy;
365         XButtonEvent *bevent = (XButtonEvent *)event;
366         XtVaGetValues(widget, XmNuserData, &palitem, NULL);
367
368         /* Creation may take awhile, so set busy cursor */
369         xy_win = x_xwin_at_rootxy(AB_toplevel, bevent->x_root, 
370                         bevent->y_root, &wx, &wy);
371         ab_set_busy_cursor(TRUE);
372         ui_set_busy_cursor(xy_win, TRUE);
373
374         obj = obj_create(palitem->type, NULL);
375
376         if (palitem->type == AB_TYPE_SCALE)
377             obj_set_read_only(obj, subtype);
378
379         if (subtype != AB_NO_SUBTYPE)
380             obj_set_subtype(obj, subtype);
381
382         if (errmsg = locate_obj_parent(obj, widget, bevent->x_root, 
383                 bevent->y_root, &obj_parent, &ModuleCreated))
384         {
385             obj_destroy(obj);
386             if (!util_streq(errmsg, ""))
387             {
388                 xm_buf = XmStringCreateLocalized(errmsg);
389                 dtb_palette_error_msg_initialize(&dtb_palette_error_msg);
390                 (void)dtb_show_modal_message(dtb_get_toplevel_widget(), 
391                         &dtb_palette_error_msg, xm_buf, NULL, NULL);
392                 XmStringFree(xm_buf);
393             }
394         }
395         else
396         {
397             if (pal_initialize_obj(obj) == ERROR)
398                 fprintf(stderr, "create_obj_action: couldn't initialize object\n");
399             else if (abobj_show_tree(obj, TRUE) == -1)
400                 fprintf(stderr,"create_obj_action: couldn't show object\n");
401             else
402             {
403                 /* set the initial visiblity of new layers to false */
404                 if (obj_is_layers(obj_parent))
405                     obj_set_is_initially_visible(obj, FALSE);
406                 
407                 /* Deselect any objects that happen to be selected */
408                 abobj_deselect_all(project);
409                 aob_deselect_all_objects(project);
410
411                 /* Make the new obj selected */
412                 abobj_select(obj);
413
414                 /* Set the dirty bit on the module */
415                 abobj_set_save_needed(obj_get_module(obj), TRUE);
416
417                 /* If the window is the first one dragged out and 
418                  * its parent (the module) has not been named yet, 
419                  * popup the module name dialog.  The only time a
420                  * module will have not been named by the user is
421                  * when it is created at the time the first window
422                  * is dragged from the palette.
423                  */
424                 if( obj_is_window(obj) && ModuleCreated )
425                 {
426                     /* Pop up the name dialog */
427                     proj_show_name_dlg(obj_parent, objxm_get_widget(obj));
428                 }
429                 
430                 /*
431                  * Once an object is successfully dragged out from the
432                  * palette, disable undo. Object creation is not undo-able.
433                  */
434                 abobj_cancel_undo();
435             }
436         }
437         /* Restore to original cursor */
438         ab_set_busy_cursor(FALSE);
439         ui_set_busy_cursor(xy_win, FALSE);
440     }
441 }
442
443 /*
444  * Make a cursor from the palette item's image & cursor
445  * and grab the cursor...
446  */
447 static Boolean
448 initiate_drag(
449     Widget     w, 
450     int     subtype,
451     int     *x, 
452     int     *y, 
453     int     *xhot, 
454     int     *yhot
455 )
456 {
457
458     static unsigned int   max_c_width = 0; /* The maximum cursor size */
459     static unsigned int   max_c_height = 0;
460     static Pixmap         item_pixmap = NULL;/* pixmap for cursor */
461     static GC             p_gc = NULL;       /* GC used for pixmap creation */
462     char                  *server_vendor = NULL;
463     PalItemInfo           *palitem;            /* palette obj */
464     PalSubtypeInfo        *palitem_subptr = NULL;
465     Widget                item_widget = w;   /* widget used for cursor image */
466     XRectangle            w_rect;            /* widget width,height,x,y */
467     int                   c_width, c_height; /* cursor width & height */
468     int                   cc_width, cc_height;/* copycursor width & height */
469     Display               *dpy;
470     Window                win;
471     int                   i;
472
473     if (max_c_width == 0) /* Need to Query server's Cursor constraints */
474     {
475         server_vendor = XServerVendor(XtDisplay(w));
476
477         if (strcmp(server_vendor, "Sun Microsystems, Inc.") == 0)
478         {
479             /* 
480              * On a Sun X server, a call to XQueryBestSize() will return a limit
481              * based on a *hardware* cursor;  this is misleading because the 
482              * server actually supports a much larger software cursor (only limited
483              * by the screen size); therefore set the limit based on screen size.
484              */
485             max_c_width = WidthOfScreen(XtScreen(w));
486             max_c_height = HeightOfScreen(XtScreen(w));
487         }
488         else
489             /* Ask for a big size to get the maximum */
490             XQueryBestSize(XtDisplay(w), CursorShape, XtWindow(w), 1000, 1000, 
491                 &max_c_width, &max_c_height);
492
493         util_dprintf(0, "For Server(%s) Max Cursor size = %dx%d\n", 
494                 server_vendor, max_c_width, max_c_height);
495         /* 
496          * Need to leave room for the outlining of the object's image
497          * which is taken care of in x_create_stencil_cursor().
498          */
499         max_c_width -= 2;
500         max_c_height -= 2;
501     }
502
503     XtVaGetValues(w, 
504                         XmNuserData,    &palitem, 
505                         XtNwidth,       &(w_rect.width),
506                         XtNheight,      &(w_rect.height), 
507                         XtNx,           &(w_rect.x),
508                         XtNy,           &(w_rect.y), 
509                         NULL);
510     /*
511      * Create Drag Cursor containing item's image
512      */
513
514     /*
515      * If item is a choice setting or textfield, need to
516      * use the parent container's image for the cursor;
517      * also must translate the cursor x,y position to
518      * the parent's rectangle coordinates
519      *
520      * NOTE:
521      * For SpinBox, this is done if the widget passed
522      * is not a subclass of spinbox. (We cannot assume
523      * what these widgets are composed of).
524      */
525     if ((palitem->type == AB_TYPE_CHOICE &&
526             XtIsSubclass(w, xmToggleButtonWidgetClass)) || 
527         (palitem->type == AB_TYPE_CONTAINER  &&
528             XtIsSubclass(w, xmCascadeButtonWidgetClass)) ||
529         (palitem->type == AB_TYPE_TEXT_FIELD && 
530             (XtIsSubclass(w, xmLabelWidgetClass) ||
531                         XtIsSubclass(w, xmTextFieldWidgetClass))) ||
532         (palitem->type == AB_TYPE_SPIN_BOX && 
533             !XtIsSubclass(w, dtSpinBoxWidgetClass)) ||
534         (palitem->type == AB_TYPE_COMBO_BOX && 
535             !XtIsSubclass(w, dtComboBoxWidgetClass)) ||
536         (palitem->type == AB_TYPE_SCALE &&
537             !XtIsSubclass(w, xmScaleWidgetClass)))
538     {
539         item_widget = XtParent(w);
540
541         *x +=  w_rect.x;
542         *y +=  w_rect.y;
543
544         XtVaGetValues(item_widget,
545                         XmNuserData,    (XtArgVal)&palitem,
546                         XtNwidth,       (XtArgVal)&(w_rect.width), 
547                         XtNheight,      (XtArgVal)&(w_rect.height),  
548                         NULL);
549     }
550         
551     dpy = (Display *)XtDisplay(item_widget);
552     win = (Window)   XtWindow(item_widget);
553
554     cc_width  = AB_cp_cursor_width;
555     cc_height = AB_cp_cursor_height;
556
557     if (dtb_app_resource_rec.use_small_drag_cursor == FALSE)
558     {
559         c_width   = AB_max_item_width  + cc_width  + 4;
560         c_height  = AB_max_item_height + cc_height + 4;
561     }
562     else /* Need Drag Cursor <= 32x32 */
563     {
564         c_width   = 28;
565         c_height  = 28;
566     }
567
568     /* 
569      * Ensure cursor is within server limits
570      * Note that on some servers (HP, IBM) the cursor limitation
571      * will cause some object drag-cursors to be cropped.
572      * Unfortunately, for 1.0, there is nothing we can do about
573      * this.
574      */
575     if (c_width > max_c_width)
576         c_width = max_c_width;
577     if (c_height > max_c_height)
578         c_height = max_c_height;
579
580     if (!p_gc) /* First-time thru: Create Cursor pixmaps & GC */
581     {
582         XGCValues          values;
583         Pixel      fg_pixel, bg_pixel;
584
585         item_pixmap = XCreatePixmap(dpy, win, c_width, c_height, 1);
586  
587         fg_pixel = BlackPixelOfScreen(XtScreen(item_widget));
588         bg_pixel = WhitePixelOfScreen(XtScreen(item_widget));
589  
590         values.foreground = fg_pixel;
591         values.background = bg_pixel;
592         p_gc = XCreateGC(dpy, item_pixmap, GCForeground|GCBackground, &values);
593     }
594
595     /* Find the appropriate palette pixmap for the object subtype */
596     for (i=0; i < palitem->num_subinfo; i++)
597         if (palitem->subinfo[i].subtype == subtype)
598         {
599             palitem_subptr = &(palitem->subinfo[i]);
600             break;
601         }
602
603     /* This should never happen! */
604     if (palitem_subptr == NULL)
605     {
606         util_dprintf(0,"initiate_drag: could not find palette object subtype info\n");
607         return FALSE;
608     }
609
610     if (!palitem_subptr->pixmap)
611     {
612         XImage    *item_image;
613             
614         item_image = build_item_image(item_widget);
615         /* no error recovery here. Do we care? */
616
617         palitem_subptr->pmwidth  = w_rect.width  + 4;
618         palitem_subptr->pmheight = w_rect.height + 4;
619         palitem_subptr->pixmap = XCreatePixmap(dpy, win, palitem_subptr->pmwidth, 
620                 palitem_subptr->pmheight, 1);
621
622         XSetFunction(dpy, p_gc, GXclear);
623         XFillRectangle(dpy, palitem_subptr->pixmap, p_gc, 0, 0, 
624                 w_rect.width + 4, w_rect.height + 4);
625
626         XSetFunction(dpy, p_gc, GXcopy);
627         XPutImage(dpy, palitem_subptr->pixmap, p_gc, item_image, 0, 0,
628             2, 2, item_image->width, item_image->height);
629     
630         XDestroyImage(item_image);
631     }
632
633     XSetFunction(dpy, p_gc, GXclear);
634     XFillRectangle(dpy, item_pixmap, p_gc, 0, 0, c_width, c_height);
635
636     XSetFunction(dpy, p_gc, GXcopy);
637     if (dtb_app_resource_rec.use_small_drag_cursor == FALSE)
638     {
639         /* Copy the item's image pixmap onto the cursor_pixmap */
640         XCopyArea(dpy, palitem_subptr->pixmap, item_pixmap, p_gc, 0, 0,
641             c_width, c_height, 0, 0);
642
643         *xhot = *x + 2;
644         *yhot = *y + 2;
645     }
646     else  /* dtb_app_resource_rec.use_small_drag_cursor == TRUE */
647     {
648         int rw, rh;
649         BOOL is_win = FALSE;
650
651         /* Render a simple shape describing basic type of 
652          * object is being dragged....
653          */
654         switch(palitem->type)
655         {
656             case AB_TYPE_BASE_WINDOW:
657             case AB_TYPE_DIALOG:
658                 rw = 25;
659                 rh = 16;
660                 is_win = TRUE;
661                 *xhot = 6;
662                 *yhot = 6;
663                 break;
664             case AB_TYPE_CONTAINER:
665             case AB_TYPE_DRAWING_AREA:
666             case AB_TYPE_TEXT_PANE:
667             case AB_TYPE_TERM_PANE:
668                 rw = 24;
669                 rh = 15;
670                 *xhot = 6;
671                 *yhot = 6;
672                 break;
673             default: /* Controls */
674                 rw = 24;
675                 rh = 10;
676                 *xhot = 5;
677                 *yhot = 5;
678         }
679         XDrawRectangle(dpy, item_pixmap, p_gc, 0, 0, rw, rh);
680         if (is_win)
681             XDrawLine(dpy, item_pixmap, p_gc, 0, 4, rw, 4);
682
683     }
684
685     /* overlay image of copycursor on item image */
686     XSetFunction(dpy, p_gc, GXor);
687     x_graphics_op(dpy, item_pixmap, p_gc, *xhot, *yhot,
688                         cc_width, cc_height, AB_cp_cursor_pixmap);
689
690     /*
691      * Ensure hot-spot is within server cursor size
692      */
693     if (*xhot > c_width)
694         *xhot = c_width - 4;
695     if (*yhot > c_height)
696         *yhot = c_height - 4;
697
698     drag_cursor = x_create_stencil_cursor(item_widget, item_pixmap,
699             c_width, c_height, *xhot, *yhot);
700
701     if (XGrabPointer(dpy, win, FALSE, 
702             ButtonReleaseMask | PointerMotionMask,
703             GrabModeAsync, GrabModeAsync, None, drag_cursor,
704             CurrentTime) == GrabSuccess)
705         return TRUE;
706     else
707         XFreeCursor(dpy, drag_cursor);
708
709     return FALSE;
710
711 }
712
713 /*
714  * Get a 1-bit image of the palette item
715  */
716 static XImage *
717 build_item_image(
718     Widget widget
719 )
720 {
721     XRectangle          w_rect;
722     Window              win;
723     Display             *dpy;
724     XImage              *get_image, 
725                         *new_image;
726     XWindowAttributes   attr;
727     char                *new_image_data;
728
729     /*
730      * Get the item's bounding rect and other associated information.
731      */
732     x_get_widget_rect(widget, &w_rect);
733
734     win   = (Window)XtWindow(widget);
735     dpy   = (Display *)XtDisplay(widget);
736
737     /*
738      * Get the item's image and it's attributes (including visual).
739      */
740     get_image = XGetImage(dpy,
741                   win,
742                   0,
743                   0,
744                   w_rect.width,
745                   w_rect.height,
746                   AllPlanes,
747                   XYPixmap);
748
749     XGetWindowAttributes(dpy, win, &attr);
750
751     /*
752      * Create a new blank image.
753      */
754     new_image_data = (char *)XtMalloc((w_rect.width * w_rect.height) * sizeof(char));
755     new_image = XCreateImage(dpy,
756                  attr.visual,
757                  1,
758                  XYBitmap,
759                  0,
760                  new_image_data,
761                  w_rect.width,
762                  w_rect.height,
763                  8,
764                  0);
765
766     /*
767      * Copy the specified planes from the "get" image to the new image.
768      */
769     image_copy(widget, get_image, new_image, w_rect.width, 0, 0);
770
771     XDestroyImage(get_image);
772     return(new_image);
773 }
774
775
776 /*
777  * Copy item's outline image to a 1 bit image
778  */
779 static void
780 image_copy(
781     Widget     widget, 
782     XImage     *from_image, 
783     XImage     *to_image, 
784     int     image_width, 
785     int     get_x, 
786     int     put_x
787 )
788 {
789     register int    i, j, k, pix;
790     Pixel           background;
791     Pixel           foreground;
792     Pixel           bshadow, tshadow;
793     Pixel           black, white;
794  
795     /*
796      * Only draw bits that are not part of the background and, if
797      * color, the depression color (BG2).
798      */
799     XtVaGetValues(widget, 
800                 XtNbackground,          &background, 
801                 XtNforeground,          &foreground,
802                 XmNbottomShadowColor,   &bshadow,
803                 XmNtopShadowColor,      &tshadow,
804                 NULL);
805
806     black = BlackPixelOfScreen(XtScreen(widget));
807     white = WhitePixelOfScreen(XtScreen(widget));
808  
809     for (i = 0; i < from_image->height; i++)
810     {
811         for (j = get_x, k = put_x; j < image_width; j++, k++)
812         {
813             pix = XGetPixel(from_image, j, i);
814             if ((pix == foreground || 
815                 pix == bshadow ||
816                 pix == tshadow ||
817                 pix == black || 
818                 pix == white) &&
819                 pix != background)
820                 XPutPixel(to_image, k, i, black);
821             else
822                 XPutPixel(to_image, k, i, white);
823          }
824     }
825 }
826
827 /*
828  * Figure out which ui object the palette item was dropped on
829  */
830 static char *
831 locate_obj_parent(
832     ABObj   obj, 
833     Widget  widget, 
834     int     x, 
835     int     y,
836     ABObj   *parentptr,
837     BOOL    *ModuleCreated
838 )
839 {
840     ABObj               project = proj_get_project();
841     ABObj               module  = proj_get_cur_module();
842     ABObj               obj_parent = (ABObj) NULL;
843     Display             *dpy = (Display *)XtDisplay(widget);
844     int                 w_x, w_y;
845     DTB_MODAL_ANSWER    answer = DTB_ANSWER_NONE;
846     STRING              errmsg = (STRING) NULL;
847     STRING              i18n_msg = (STRING) NULL;
848
849     *ModuleCreated = FALSE;
850
851     if (obj_is_window(obj))
852     {
853         if (x_rootxy_inside_widget(palette_widget, x, y))
854             return "";
855
856         if ( module == NULL )
857         {
858             obj_parent = obj_create(AB_TYPE_MODULE, project);
859             obj_set_name(obj_parent, "module");
860             abobj_show_tree(obj_parent, FALSE);
861             proj_set_cur_module(obj_parent);
862             *ModuleCreated = TRUE;
863         }
864         else
865         {
866             obj_parent = module;
867         }
868         obj_append_child(obj_parent, obj);
869
870         obj->x = x - drag_cursor_xhot;
871         obj->y = y - drag_cursor_yhot;
872     }
873     else 
874     {
875         obj_parent = locate_obj_at_rootxy(x, y, &w_x, &w_y);
876
877         obj->x = w_x - drag_cursor_xhot;
878         obj->y = w_y - drag_cursor_yhot;
879
880         /* If not dropped on an object, but is still within
881          * palette, just ignore the drag...
882          */
883         if (obj_parent == NULL &&
884             x_rootxy_inside_widget(palette_widget, x, y))
885             return "";
886
887         if (obj_is_menubar(obj))
888         {
889             AB_TRAVERSAL        trav;
890             ABObj               winobj;
891             ABObj               nobj;
892
893             if (obj_parent != NULL)
894             {
895                 winobj = obj_parent;
896                 while(!(obj_is_window(winobj) && !obj_is_sub(winobj)))
897                     winobj = obj_get_parent(winobj);
898
899                 if (!obj_is_base_win(winobj))
900                     obj_parent = NULL;
901                 else /* Check to make sure there isn't already a Menubar for
902                       * this window
903                       */
904                 {
905                     for (trav_open(&trav, winobj, AB_TRAV_UI);
906                         (nobj = trav_next(&trav)) != NULL; )
907                         if (obj_is_menubar(nobj))
908                         {
909                             i18n_msg = catgets(Dtb_project_catd, 100, 11,
910                                 "There is already a Menubar for this window.");
911
912                             /* If we have an old buffer lying around, free it */
913                             if (errmsg != (STRING) NULL) 
914                                 util_free(errmsg);
915
916                             errmsg = (STRING) util_malloc(strlen(i18n_msg) + 1);
917                             strcpy(errmsg, i18n_msg); 
918                             return (errmsg);
919                         }
920
921                     obj_parent = objxm_comp_get_subobj(winobj, AB_CFG_MENU_PARENT_OBJ);
922                 }
923             }
924             if (obj_parent == NULL)
925             {
926                 i18n_msg = catgets(Dtb_project_catd, 100, 15,
927                         "Menubars must be dropped on a Main Window.");
928
929                 /* If we have an old buffer lying around, free it */
930                 if (errmsg != (STRING) NULL)
931                     util_free(errmsg);
932
933                 errmsg = (STRING) util_malloc(strlen(i18n_msg) + 1);
934                 strcpy(errmsg, i18n_msg);
935                 return (errmsg);
936             }
937
938         }
939         else if (obj_is_container(obj) && !obj_is_control_panel(obj))
940         {
941             if (obj_parent == NULL ||
942                 (!(obj_is_container(obj_parent) &&
943                 obj_is_sub(obj_parent) &&
944                 obj_is_window(obj_get_root(obj_parent)) &&
945                 !obj_is_file_chooser(obj_parent))))
946             {
947                 i18n_msg = catgets(Dtb_project_catd, 100, 12,
948                         "Containers must be dropped on\na Main Window or Custom Dialog."); 
949                 /* If we have an old buffer lying around, free it */     
950                 if (errmsg != (STRING) NULL)
951                     util_free(errmsg);
952  
953                 errmsg = (STRING) util_malloc(strlen(i18n_msg) + 1);
954                 strcpy(errmsg, i18n_msg);
955                 return (errmsg);
956             }
957         }
958         else if (obj_is_pane(obj))
959         {
960             if (obj_parent != NULL && 
961                 (obj_is_pane(obj_parent) &&
962                  !obj_is_window(obj_get_root(obj_parent))))
963             {
964                 ABObj   grandparent = NULL;
965                 ABObj   great_grandparent = NULL;
966                 grandparent = obj_get_parent(obj_get_root(obj_parent));
967                 great_grandparent = obj_get_parent(grandparent);
968
969                 /* The child is a textpane, termpane, or drawing area
970                  * and the parent (object being dropped upon) is a   
971                  * control pane that is not part of a panedWindow.
972                  */ 
973                 if (!obj_is_control_panel(obj) && 
974                     obj_is_control_panel(obj_parent) &&
975                     !obj_is_paned_win(grandparent))
976                 {
977                     /* If the parent of obj_parent is a layered pane
978                      * then we have to check if the layered pane is
979                      * a child of a panedwindow. If so, then we should
980                      * ask the user whether he wants to make the pane
981                      * a child of the control pane, a new layer, or
982                      * a new pane in the paned window.
983                      */
984                     if (obj_is_layers(grandparent) && 
985                         obj_is_paned_win(great_grandparent))
986                     {
987                         dtb_palette_chld_layr_pw_msg_initialize(
988                                 &dtb_palette_chld_layr_pw_msg);
989                         answer = dtb_show_modal_message(
990                                 (Widget)obj_parent->ui_handle,
991                                 &dtb_palette_chld_layr_pw_msg,
992                                 NULL, NULL, NULL);
993                         switch(answer)
994                         {
995                             /* Create as a child of the control pane */
996                             case DTB_ANSWER_ACTION1:
997                                 break;
998
999                             /* Create as a new layer */
1000                             case DTB_ANSWER_ACTION2:
1001                                 obj_parent = abobj_handle_layered_pane(obj, obj_parent);
1002                                 break;
1003
1004                             /* Create as a new pane in the paned window */
1005                             case DTB_ANSWER_ACTION3:
1006                                 obj_parent = great_grandparent;
1007                                 break;
1008
1009                             case DTB_ANSWER_CANCEL:
1010                                 return "";
1011                         }
1012                     }
1013                     else
1014                     {
1015                         /* Popup Modal Message and wait for answer */
1016                         dtb_palette_chld_or_layr_msg_initialize(
1017                                 &dtb_palette_chld_or_layr_msg);
1018                         answer = dtb_show_modal_message(
1019                                 (Widget)obj_parent->ui_handle,
1020                                 &dtb_palette_chld_or_layr_msg, 
1021                                 NULL, NULL, NULL);
1022                         switch(answer)
1023                         {
1024                             case DTB_ANSWER_ACTION1: /* As Child */
1025                             break;
1026
1027                             case DTB_ANSWER_ACTION2: /* As Layered Pane */
1028                             obj_parent = abobj_handle_layered_pane(obj, obj_parent);
1029                             break;
1030
1031                             case DTB_ANSWER_CANCEL:
1032                             return "";
1033                         }
1034                     }
1035                 }
1036                 /* The child is a control pane or the parent is
1037                  * not a control pane (i.e. a textpane child of
1038                  * a control pane). The parent is not part of a
1039                  * panedWindow.
1040                  */
1041                 else if (!obj_is_paned_win(grandparent))
1042                 {
1043                     /* If Pane was dropped on a Pane which is a NORMAL child of
1044                      * a Control Pane, then use the Control Pane as the actual
1045                      * parent instead of the pane.
1046                      */
1047                     if (obj_is_control_panel(obj_get_root(grandparent)))
1048                     {
1049                         obj_parent = grandparent;
1050                     }
1051  
1052                     /* Check if the grandparent is a layered pane.
1053                      * If so, then we have to check it is part of
1054                      * a panedwindow. If it is, then we need to
1055                      * ask the user whether to create the pane as
1056                      * a layered pane or a new pane in the paned
1057                      * window.
1058                      */
1059                     if (obj_is_layers(grandparent) &&
1060                         obj_is_paned_win(great_grandparent))
1061                     {
1062                         dtb_palette_layr_pw_msg_initialize(
1063                                 &dtb_palette_layr_pw_msg);
1064                         answer = dtb_show_modal_message(
1065                                 (Widget)obj_parent->ui_handle,
1066                                 &dtb_palette_layr_pw_msg,
1067                                 NULL, NULL, NULL);
1068                         switch(answer)
1069                         {
1070                             case DTB_ANSWER_ACTION1: /* Layered Pane */
1071                                 obj_parent = abobj_handle_layered_pane(obj, obj_parent);
1072                                 break;
1073  
1074                             case DTB_ANSWER_ACTION2: /* PanedWindow Pane */
1075                                 obj_parent = grandparent;
1076                                 break;
1077
1078                             case DTB_ANSWER_CANCEL:
1079                                 return "";
1080  
1081                             case DTB_ANSWER_HELP:
1082                                 break;
1083                         }
1084                     }
1085                     else
1086                     {
1087                         /* Popup Modal Message and wait for answer */
1088                         dtb_palette_layered_pane_msg_initialize(
1089                                 &dtb_palette_layered_pane_msg);
1090                         answer = dtb_show_modal_message(
1091                                 (Widget)obj_parent->ui_handle,
1092                                 &dtb_palette_layered_pane_msg, 
1093                                 NULL, NULL, NULL);
1094                         switch(answer)
1095                         {
1096                             case DTB_ANSWER_ACTION2: /* Layered Pane */
1097                                 obj_parent = abobj_handle_layered_pane(obj, obj_parent);
1098                                 break;
1099
1100                             case DTB_ANSWER_CANCEL: /* Cancel */
1101                                 return "";
1102                         }
1103                     }
1104                 }
1105                 /* A termpane, textpane, or draw area is being dropped
1106                  * on another pane (not control pane) and that pane
1107                  * is inside a paned window.
1108                  *
1109                  * OR
1110                  *
1111                  * The object being dragged is a control pane and
1112                  * the parent is part of a panedWindow.
1113                  */
1114                 else if (!obj_is_control_panel(obj_parent) ||
1115                          obj_is_control_panel(obj))
1116                 {
1117                     dtb_palette_layr_pw_msg_initialize(
1118                                 &dtb_palette_layr_pw_msg);
1119                     answer = dtb_show_modal_message(
1120                                 (Widget)obj_parent->ui_handle,
1121                                 &dtb_palette_layr_pw_msg, 
1122                                 NULL, NULL, NULL);
1123                     switch(answer)
1124                     {
1125                         case DTB_ANSWER_ACTION1: /* Layered Pane */ 
1126                             obj_parent = abobj_handle_layered_pane(obj, obj_parent);
1127                             break;
1128  
1129                         case DTB_ANSWER_ACTION2: /* PanedWindow Pane */
1130                             obj_parent = grandparent;
1131                             break;
1132
1133                         case DTB_ANSWER_CANCEL: 
1134                             return "";
1135
1136                         case DTB_ANSWER_HELP:
1137                             break;
1138                     }
1139                 }
1140                 /* The obj is a textpane, termpane, or draw area
1141                  * and the parent of obj_parent is a panedWindow.
1142                  */
1143                 else
1144                 {
1145                     dtb_palette_chld_layr_pw_msg_initialize(
1146                                 &dtb_palette_chld_layr_pw_msg);
1147                     answer = dtb_show_modal_message(
1148                                 (Widget)obj_parent->ui_handle,
1149                                 &dtb_palette_chld_layr_pw_msg, 
1150                                 NULL, NULL, NULL);
1151                     switch(answer)
1152                     {
1153                         /* Create as a child of the control pane */
1154                         case DTB_ANSWER_ACTION1:
1155                             break;
1156
1157                         /* Create as a new layer */
1158                         case DTB_ANSWER_ACTION2:
1159                             obj_parent = abobj_handle_layered_pane(obj, obj_parent);
1160                             break;
1161
1162                         /* Create as a new pane in the paned window */
1163                         case DTB_ANSWER_ACTION3:
1164                             obj_parent = obj_get_parent(obj_parent);
1165                             break;
1166
1167                         case DTB_ANSWER_CANCEL:
1168                             return "";
1169                     }
1170                 }
1171             }
1172             /*
1173              * Dropping panes onto a group
1174              */
1175             else if (obj_parent != NULL && obj_is_group(obj_parent))
1176             {
1177                 if (obj_is_control_panel(obj))
1178                 {
1179                     i18n_msg = catgets(Dtb_project_catd, 100, 59,
1180                         "Control Panes must be dropped on a Main Window,\nCustom Dialog, or another pane.");
1181
1182                     /* If we have an old buffer lying around, free it */
1183  
1184                     if (errmsg != (STRING) NULL)
1185                         util_free(errmsg);
1186   
1187                     errmsg = (STRING) util_malloc(strlen(i18n_msg) + 1);
1188                     strcpy(errmsg, i18n_msg); 
1189                     return (errmsg); 
1190                 }
1191                 else
1192                 {
1193                     dtb_palette_child_of_group_msg_initialize(
1194                                 &dtb_palette_child_of_group_msg);
1195                     answer = dtb_show_modal_message(
1196                                 (Widget)obj_parent->ui_handle,
1197                                 &dtb_palette_child_of_group_msg, 
1198                                 NULL, NULL, NULL);
1199                     switch(answer)
1200                     {
1201                         /* OK - Create as a child of group */
1202                         case DTB_ANSWER_ACTION1:
1203                             break;
1204
1205                         case DTB_ANSWER_CANCEL:
1206                             return "";
1207                     }
1208                 }
1209             }
1210             else if (obj_parent == NULL ||
1211                 (!(obj_is_container(obj_parent) &&
1212                 !obj_is_menubar(obj_parent))))
1213             {
1214                 i18n_msg = catgets(Dtb_project_catd, 100, 13,
1215                         "Panes must be dropped on a Main Window,\nCustom Dialog, or another pane.");
1216
1217                 /* If we have an old buffer lying around, free it */
1218  
1219                 if (errmsg != (STRING) NULL)
1220                     util_free(errmsg);
1221   
1222                 errmsg = (STRING) util_malloc(strlen(i18n_msg) + 1);
1223                 strcpy(errmsg, i18n_msg); 
1224                 return (errmsg); 
1225             }
1226
1227         }
1228         else if (obj_is_control(obj))
1229         {
1230             if (obj_parent == NULL ||
1231                 (!obj_is_control_panel(obj_get_root(obj_parent)) && 
1232                 !obj_is_group(obj_get_root(obj_parent))))
1233             {
1234                 i18n_msg = catgets(Dtb_project_catd, 100, 14, 
1235                         "Controls must be dropped on\na Control Pane or Group."); 
1236                 /* If we have an old buffer lying around, free it */
1237                 if (errmsg != (STRING) NULL) 
1238                     util_free(errmsg); 
1239   
1240                 errmsg = (STRING) util_malloc(strlen(i18n_msg) + 1); 
1241                 strcpy(errmsg, i18n_msg);  
1242                 return (errmsg);
1243             }
1244
1245         }
1246         else
1247         {
1248             i18n_msg = catgets(Dtb_project_catd, 100, 16,
1249                         "Unknown object type.");
1250
1251             /* If we have an old buffer lying around, free it */
1252             if (errmsg != (STRING) NULL)
1253                     util_free(errmsg);
1254
1255             errmsg = (STRING) util_malloc(strlen(i18n_msg) + 1);
1256             strcpy(errmsg, i18n_msg);
1257             return (errmsg);
1258         }
1259
1260         obj_append_child(obj_parent, obj);
1261     }
1262
1263     *parentptr = obj_parent;
1264     return NULL;
1265
1266 }
1267
1268 ABObj
1269 locate_obj_at_rootxy(
1270     int     x,
1271     int     y,
1272     int     *p_wx,
1273     int     *p_wy
1274 )
1275 {
1276     ABObj           project = proj_get_project();
1277     ABObj           obj     = project;
1278     AB_TRAVERSAL    trav;
1279     Window          window;
1280     Widget          widget;
1281  
1282     if (obj == NULL)
1283         return NULL;
1284
1285     window = x_xwin_at_rootxy(AB_toplevel, x, y, p_wx, p_wy);
1286     if (window == 0)
1287         return NULL;
1288
1289     for (trav_open(&trav, obj, AB_TRAV_UI);
1290         (obj = trav_next(&trav)) != NULL; )
1291     {
1292         widget = (Widget)obj->ui_handle;
1293  
1294         if (widget != NULL &&
1295             XtIsRealized(widget) &&
1296             XtWindow(widget) == window)
1297         {
1298             return obj;
1299         }
1300     }
1301
1302     /*
1303      * Are we in the draw area of any browser window ?
1304      */
1305     if (aob_is_browser_win(project, window))
1306     {
1307         ABObj   browser_obj;
1308
1309         /*
1310          * Get the ABObj that the ptr is currently above
1311          */
1312         browser_obj = aob_get_object_from_xy(project, window, *p_wx, *p_wy);
1313
1314         if (browser_obj)
1315         {
1316             /*
1317              * Return the config parent of the ABObj.
1318              * This needs to be done because the ABObj shown on the 
1319              * browser and the ABObj of the interface objects as 
1320              * seen by the user are different things.
1321              *
1322              * Also, since we are dealing with browser coordinates
1323              * here (and not precise positions on the parent obj), 
1324              * set the position (x,y) to some default.
1325              *
1326              * drag_cursor_[x,y]hot is added here because it is 
1327              * subtracted later to determine the exact position
1328              * of the object.
1329              */
1330             *p_wx = AB_DEFAULT_X + drag_cursor_xhot;
1331             *p_wy = AB_DEFAULT_Y + drag_cursor_yhot;
1332             return (objxm_comp_get_subobj(browser_obj, AB_CFG_PARENT_OBJ));
1333         }
1334     }
1335
1336     return NULL;
1337
1338 }