dtwm: Cleanup some implicit definitions
[oweals/cde.git] / cde / programs / dtwm / Callback.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: Callback.c /main/10 1996/10/30 11:14:26 drk $ */
24 /*****************************************************************************
25  *
26  *   File:         Callback.c
27  *
28  *   Project:       CDE
29  *
30  *   Description:  This file contains the user interface behavior processing
31  *                 functions for the CDE front panel
32  *
33  * (c) Copyright 1993, 1994 Hewlett-Packard Company
34  * (c) Copyright 1993, 1994 International Business Machines Corp.
35  * (c) Copyright 1993, 1994 Sun Microsystems, Inc.
36  * (c) Copyright 1993, 1994 Novell, Inc.
37  *
38  ****************************************************************************/
39
40 #include <sys/param.h>
41 #include <sys/stat.h>
42
43 #include <Dt/DtP.h>
44 #include <Dt/DbReader.h>
45 #include "PanelSP.h"
46 #include <Dt/Control.h>
47 #include <Dt/ControlP.h>
48 #include <Dt/IconFile.h>
49 #include <Dt/Icon.h>
50 #include <Dt/Dnd.h>
51 #include <Dt/Dts.h>
52 #include <Dt/Action.h>
53 #include <Dt/DtNlUtils.h>
54 #include <Dt/WsmP.h>
55 #include <Dt/WsmM.h>
56 #include <Dt/MacrosP.h>
57
58 #include <Xm/Form.h>
59 #include <Xm/ToggleBG.h>
60 #include <Xm/AtomMgr.h>
61 #include <Xm/TextF.h>
62
63 #include <X11/Xatom.h>
64 #include <X11/keysym.h>
65
66 #include "DataBaseLoad.h"
67 #include "UI.h"
68
69 #include "WmGlobal.h"
70 #include "WmResNames.h"
71 #include "WmFunction.h"
72
73
74 /************************************************************************
75  *
76  *  External and static function declarations.
77  *
78  ************************************************************************/
79
80 extern XtPointer _XmStringUngenerate(XmString, XmStringTag,
81                                      XmTextType, XmTextType);
82
83 extern void SubpanelControlCreate (SubpanelData *, ControlData *, ControlData *,
84                                    Widget, Boolean, Boolean);
85 extern void WmSubpanelPosted (Display *, Window);
86 extern int PushRecallGetData (char *);
87 extern void SwitchButtonCreate (SwitchData *, Boolean);
88 extern void AddControlActionList (ControlData *);
89
90 void ArrowCB (Widget, XtPointer, XtPointer); 
91 void HandleInputCB (Widget, XtPointer, XtPointer); 
92 void MinimizeInputCB (Widget, XtPointer, XtPointer); 
93 void MenuInputCB (Widget, XtPointer, XtPointer); 
94 void SwitchButtonCB (Widget, XtPointer, XtPointer);
95 void PushCB (Widget, XtPointer, XtPointer);
96 void SubpanelUnmapCB (Widget, XtPointer, XtPointer); 
97 void SubpanelTornEventHandler (Widget, XtPointer, XEvent *, Boolean *);
98 Boolean CheckControlTypeFile (ControlData *);
99
100
101 static void SwitchRenameCancel (Widget, XEvent *, String *, Cardinal *);
102 static void SwitchRenameCB (Widget, XtPointer, XtPointer);
103 static void GetValuesFromDataType(char *, char *, SubpanelData *,
104                                   ElementValue **);
105
106 void SwitchRenameLabel (Widget, BoxData *);
107 void DropCB (Widget, XtPointer, XtPointer); 
108 void TransferDropCB (Widget, XtPointer, XtPointer); 
109 void CustomizeDropCB (Widget, XtPointer, XtPointer);
110 void CustomizeTransferDropCB (Widget, XtPointer, XtPointer); 
111
112
113
114
115
116 /*  Translations and action definitions                         */
117 /*      These are used specifically for the text field overlay  */
118 /*      on the switch button for renaming the workspace.  They  */
119 /*      are necessary for handling escape key processing.       */
120
121 static char translations_escape[] = "<Key>osfCancel:Escape()";
122
123 static XtActionsRec action_table[] = {
124    {"Escape", SwitchRenameCancel},
125 };
126
127
128
129 /************************************************************************
130  *
131  *  File local globals.
132  *
133  ************************************************************************/
134
135 extern String post_arrow_image;
136 extern String unpost_arrow_image;
137 extern String post_monitor_arrow_image;
138 extern String unpost_monitor_arrow_image;
139 extern String blank_arrow_image;
140 extern String dropzone_image;
141 extern String indicator_on_image;
142 extern String indicator_off_image;
143
144
145
146 /************************************************************************
147  *
148  *  CallWmFunction
149  *      Call the specified WmFunction function with appropriate args
150  *
151  ************************************************************************/
152
153
154 void
155 CallWmFunction (WmFunction wm_function,
156                 String     args,
157                 Widget     client,
158                 XEvent   * event)
159
160
161 {
162    WmGlobalData * wm_global_data = (WmGlobalData *) panel.global_data;
163    ClientData   * wm_client_data = NULL;
164    Display      * display = wm_global_data->display;
165    Window         client_window = XtWindow(client);
166
167    /*
168     * Find the window manager client data for this client
169     */
170
171    XFindContext (display, client_window, wm_global_data->windowContextType,
172                     (XtPointer) &wm_client_data);
173
174    if (wm_client_data == NULL)
175       return;
176
177    /*  
178     * Execute the window manager function
179     */
180
181    wm_function (args, wm_client_data, event);
182 }
183
184 /************************************************************************
185  *
186  *  ArrowCB
187  *      Process the callback on the subpanel posting/unposting arrow
188  *
189  ************************************************************************/
190
191
192 void
193 ArrowCB (Widget    w,
194          XtPointer client_data,
195          XtPointer call_data) 
196
197
198 {
199    ControlData  * control_data = (ControlData *) client_data;
200    SubpanelData * subpanel_data = control_data->subpanel_data;
201
202    Arg al[2];
203    int ac;
204
205
206    /*  If the subpanel's shell is not managed, this is a request to post  */
207    /*  the subpanel.  Otherwise it is an unpost request.                  */
208    /*  Reset the arrow image after the post or unpost.                    */
209    
210    if (!XtIsManaged (subpanel_data->shell))
211    {
212       Position x = XtX (control_data->arrow);
213       Position y = XtY (control_data->arrow);
214
215
216       XtSetMappedWhenManaged (subpanel_data->shell, False);
217       XtManageChild (subpanel_data->form);
218
219       XtTranslateCoords (w, 0, 0, &x, &y);
220       x--;
221       XtSetArg (al[0], XmNx, x);
222       XtSetValues (subpanel_data->form, al, 1);
223
224       XtManageChild (subpanel_data->shell);
225       XtSetMappedWhenManaged (subpanel_data->shell, True);
226
227       ac = 0;
228       XtSetArg (al[ac], XmNimageName, unpost_arrow_image);      ac++;
229       XtSetValues (w, al, ac);
230    }
231    else
232    {
233       /*  Execute the window manager function to unpost the subpanel  */
234
235       CallWmFunction (F_Kill, NULL, subpanel_data->shell, NULL);
236    }
237 }
238
239
240
241
242 /************************************************************************
243  *
244  *  HandleInputTranslations
245  *      Return translation table suitable for HandleInputCB
246  *
247  ************************************************************************/
248
249
250 XtTranslations
251 HandleInputTranslations(void)
252
253 {
254    static XtTranslations handle_translations;
255
256    if (handle_translations == NULL)
257    {
258       handle_translations = XtParseTranslationTable(
259         "<BtnDown>:    DrawingAreaInput() ManagerGadgetArm()\n\
260          <BtnUp>:      DrawingAreaInput() ManagerGadgetActivate()\n\
261          <Btn1Motion>: DrawingAreaInput() ManagerGadgetButtonMotion()\n\
262          <Btn2Motion>: DrawingAreaInput() ManagerGadgetButtonMotion()");
263    }
264    return handle_translations;
265 }
266
267 /************************************************************************
268  *
269  *  HandleInputCB
270  *      Process button events on the frontpanel handles.
271  *
272  ************************************************************************/
273
274
275 void
276 HandleInputCB (Widget    w,
277                XtPointer client_data,
278                XtPointer call_data)
279
280
281 {
282    XmAnyCallbackStruct * callback;
283
284    XEvent       * event;
285    XButtonEvent * buttonEvent;
286    XMotionEvent * motionEvent;
287
288    callback = (XmAnyCallbackStruct *) call_data;
289    event = (XEvent *) callback->event;
290    buttonEvent = (XButtonEvent *) event;
291    motionEvent = (XMotionEvent *) event;
292
293    if (event->type == ButtonPress)
294    {
295       if (buttonEvent->button == wmGD.bMenuButton)
296       {
297          XUngrabPointer (XtDisplay (w), buttonEvent->time);
298          XSync (XtDisplay (w), FALSE);
299          CallWmFunction (F_Post_FpMenu, NULL, panel.shell, event);
300       }
301       else
302       {
303          wmGD.preMove = True;
304          wmGD.preMoveX = buttonEvent->x_root;
305          wmGD.preMoveY = buttonEvent->y_root;
306
307          if (buttonEvent->button == Button1)
308          {
309             CallWmFunction (F_Raise, NULL, panel.shell, event);
310             XSync (DISPLAY, FALSE);
311             XmUpdateDisplay (panel.shell);
312          }
313       }
314    }
315    else if (event->type == ButtonRelease)
316    {
317       wmGD.preMove = False;
318    }
319    else if (event->type == MotionNotify && wmGD.preMove)
320    {
321       int diffX, diffY;
322       
323       diffX = motionEvent->x_root - wmGD.preMoveX;
324       if (diffX < 0) diffX = -diffX;
325       diffY = motionEvent->y_root - wmGD.preMoveY;
326       if (diffY < 0) diffY = -diffY;
327
328       if (diffX >= wmGD.moveThreshold || diffY >= wmGD.moveThreshold)
329       {
330          XUngrabPointer (XtDisplay (w), motionEvent->time);
331          XSync (XtDisplay (w), FALSE);
332          CallWmFunction (F_Move, NULL, panel.shell, event);
333          wmGD.preMove = False;
334       }
335    }
336 }
337
338
339
340
341 /************************************************************************
342  *
343  *  MinimizeInputCB
344  *      Process button events on the frontpanel minimize button.
345  *
346  ************************************************************************/
347
348
349 void
350 MinimizeInputCB (Widget    w,
351                  XtPointer client_data,
352                  XtPointer call_data)
353
354
355 {
356    XmAnyCallbackStruct * callback;
357
358    XEvent       * event;
359    XButtonEvent * bevent;
360
361    extern Pixmap minimize_normal_pixmap;
362    extern Pixmap minimize_selected_pixmap;
363
364    Arg al[1];
365    
366
367    callback = (XmAnyCallbackStruct *) call_data;
368    event = (XEvent *) callback->event;
369    bevent = (XButtonEvent *) event;
370
371    /*  On the BSelect button press, change the image to the selected
372     *  minimize image.  On the release, check to see if the release
373     *  occured within the minimize button before minimizing.
374     *  On BMenu button press, post the front panel menu.
375     */
376    
377    if (event->type == ButtonPress) 
378    {
379       if (bevent->button == Button1)
380       {
381          XtSetArg (al[0], XmNbackgroundPixmap, minimize_selected_pixmap);
382          XtSetValues (w, al, 1);
383       }
384       else if (bevent->button == wmGD.bMenuButton)
385       {
386          XUngrabPointer (XtDisplay (w), bevent->time);
387          XSync (XtDisplay (w), FALSE);
388          CallWmFunction (F_Post_FpMenu, NULL, panel.shell, event);
389       }
390    }
391    else if (event->type == ButtonRelease && bevent->button == Button1)
392    {
393       if (bevent->x >= 0 && bevent->x <= (Position) XtWidth(w) &&
394           bevent->y >= 0 && bevent->y <= (Position) XtHeight(w))
395       {
396          CallWmFunction (F_Minimize, NULL, panel.shell, event);
397       }
398
399       XtSetArg (al[0], XmNbackgroundPixmap, minimize_normal_pixmap);
400       XtSetValues (w, al, 1);
401    }
402 }
403
404
405
406
407 /************************************************************************
408  *
409  *  MenuInputCB
410  *      Process button events on the front panel menu button.
411  *
412  ************************************************************************/
413
414
415 void
416 MenuInputCB (Widget    w,
417              XtPointer client_data,
418              XtPointer call_data)
419
420
421 {
422    XmAnyCallbackStruct * callback;
423
424    XEvent       * event;
425    XButtonEvent * bevent;
426
427    callback = (XmAnyCallbackStruct *) call_data;
428    event = (XEvent *) callback->event;
429    bevent = (XButtonEvent *) event;
430
431
432    /*  
433     * On BSelect or BMenu button press post the front panel system menu
434     */
435
436    if (event->type == ButtonPress && 
437        (bevent->button == Button1 || bevent->button == wmGD.bMenuButton))
438    {
439       XUngrabPointer (XtDisplay (w), bevent->time);
440       XSync (XtDisplay (w), FALSE);
441       CallWmFunction (F_Post_FpMenu, NULL, panel.shell, event);
442    }
443 }
444
445
446
447 /************************************************************************
448  ************************************************************************
449  
450     The next block of functions are used for the switch button switching,
451     renaming functionality, and add and delete of workspaces.
452     
453  ************************************************************************    
454  ************************************************************************/
455
456  
457
458 /************************************************************************
459  *
460  *  WorkspaceAdjustPanelPosition
461  *      After a workspace button has been added or deleted, if the panel
462  *      has changed sizes, reposition the panel to keep the same relative
463  *      positioning.
464  *
465  *      Inputs: x - the original x coordinate of the panel
466  *              y - the original y coordinate of the panel
467  *              width - the original width of the panel
468  *              height - the original height of the panel
469  *
470  ************************************************************************/
471
472
473 void
474 WorkspaceAdjustPanelPosition (Position x,
475                               Position y,
476                               Dimension width,
477                               Dimension height)
478
479
480 {
481    Dimension screen_width;
482    Dimension screen_height;
483    int       panel_center;
484    Dimension new_width;
485    Dimension new_height;
486    Position  new_x;            
487    Position  new_y;            
488
489    Arg al[2];
490    int ac;
491
492    screen_width = WidthOfScreen (XtScreen (panel.shell));
493    screen_height = HeightOfScreen (XtScreen (panel.shell));
494
495
496    /*  Reposition the panel to keep it centered relative to where  */
497    /*  it was positioned before the deletion of the button.        */
498          
499    ac = 0;
500
501    new_width = XtWidth (panel.shell);
502
503    if (new_width != width || x + (Position) new_width > (Position) screen_width)
504    {
505       panel_center = x + width / 2 - 1;
506       new_x = panel_center - new_width / 2 - 4;
507
508       if (new_x < 0) 
509          new_x = 0;
510       else if (new_x + (Position) new_width > (Position) screen_width) 
511          new_x = screen_width - new_width - 4;
512
513       XtSetArg (al[ac], XmNx, new_x);   ac++;
514    }
515
516
517    /*  Keep the panel to the bottom of the screen, if it was there.  */
518    /*  But make sure that it does not go below the bottom.           */
519
520    new_height = XtHeight (panel.shell);
521
522    if (new_height != height || (Dimension)(new_height + y - 1) > screen_height)
523    {
524       if (new_height < height && y > (Position)(screen_height / 2))
525       {
526          new_y = y + (Position)(height - new_height - 4);
527          XtSetArg (al[ac], XmNy, new_y);        ac++;
528       }
529       else if ((Dimension)(new_height + y - 1) > screen_height)
530       {
531          new_y = (Position)(screen_height - new_height - 4);
532          XtSetArg (al[ac], XmNy, new_y);        ac++;
533       }
534    }     
535
536    if (ac != 0)
537       XtSetValues (panel.shell, al, ac);
538 }
539  
540
541
542
543 /************************************************************************
544  *
545  *  WorkspaceModifyCB
546  *      Called by the workspace manager API to send notification of 
547  *      configuration changes to the workspace.  The types of changes
548  *      processed by this function are workspace add, delete, and rename.
549  *
550  ************************************************************************/
551
552
553 void
554 WorkspaceModifyCB (Widget    w,
555                    Atom      atom_name,
556                    int       type,
557                    XtPointer client_data)
558
559
560 {
561    SwitchData         * switch_data = (SwitchData *) client_data;
562    BoxData            * box_data = switch_data->box_data;
563    DtWsmWorkspaceInfo * workspace_info;
564
565    Position  x;
566    Position  y;
567    Dimension width;
568    Dimension height;
569    Dimension screen_width;
570
571          
572    x = XtX (panel.shell);
573    y = XtY (panel.shell);
574    width = XtWidth (panel.shell);
575    height = XtHeight (panel.shell);
576    screen_width = WidthOfScreen (XtScreen (panel.shell));
577    
578    DtWsmGetWorkspaceInfo (XtDisplay (w), RootWindowOfScreen (XtScreen (w)),
579                           atom_name, &workspace_info);
580
581    
582    switch (type)
583    {
584       /*  Increase the size of the switch names and button and call  */
585       /*  the function to create the new workspace switch button     */
586
587       case DtWSM_REASON_ADD:
588       {
589          int    switch_count;
590          Atom * atom_names;
591
592          
593          /*  Cancel workspace renaming  */
594
595          if (XtIsManaged (box_data->switch_edit))
596             SwitchRenameCancel (box_data->switch_edit, NULL, NULL, NULL);
597
598
599          DtWsmGetWorkspaceList (XtDisplay (switch_data->rc),
600                                RootWindowOfScreen (XtScreen (switch_data->rc)),
601                                &atom_names, &switch_count);
602
603          XFree (switch_data->atom_names);
604          switch_data->atom_names = atom_names;
605
606          switch_data->switch_count = switch_count;
607
608          switch_data->switch_names =
609             (char **) XtRealloc ((char *) switch_data->switch_names, 
610                                  sizeof (char *) * switch_data->switch_count);
611
612          switch_data->switch_names[switch_data->switch_count - 1] = 
613             XtNewString (workspace_info->pchTitle);
614          
615          switch_data->buttons =
616             (Widget *) XtRealloc ((char *) switch_data->buttons,
617                                  sizeof (Widget *) * switch_data->switch_count);
618
619          SwitchButtonCreate (switch_data, True);
620
621
622          /*  When adding a switch buttons, keep the row columns row count  */
623          /*  equal to the requested value with small number of buttons     */
624
625          if (switch_data->switch_count <= (int)
626              (switch_data->element_values[SWITCH_NUMBER_OF_ROWS].parsed_value))
627          {
628             Arg al[1];
629
630             panel.switch_row_count = (int)
631               (switch_data->element_values[SWITCH_NUMBER_OF_ROWS].parsed_value);
632
633             XtSetArg (al[0], XmNnumColumns, panel.switch_row_count);
634             XtSetValues (switch_data->rc, al, 1);
635          }
636
637
638          /*  If the fp width is greater than the screen, increase the  */
639          /*  row count                                                 */
640          
641          if (XtWidth (panel.shell) > screen_width)
642          {
643             Arg al[1];
644             
645             panel.switch_row_count++;
646
647             XtSetArg (al[0], XmNnumColumns, panel.switch_row_count);
648             XtSetValues (switch_data->rc, al, 1);
649          }
650
651          WorkspaceAdjustPanelPosition (x, y, width, height);
652       }
653       break;
654
655
656       /*  Loop through the current set of atom names, comparing     */
657       /*  them with the atom of the workspace to be deleted.  When  */
658       /*  free up the associated data and readjust the name, button */
659       /*  and atom lists.                                           */
660
661       case DtWSM_REASON_DELETE:
662       {
663          int i;
664          int j;
665          int    switch_count;
666          Atom * atom_names;
667          Arg al[1];
668
669          Dimension button_spacing;
670          Dimension button_width;
671
672          
673          /*  Cancel workspace renaming  */
674
675          if (XtIsManaged (box_data->switch_edit))
676             SwitchRenameCancel (box_data->switch_edit, NULL, NULL, NULL);
677
678
679          DtWsmGetWorkspaceList (XtDisplay (switch_data->rc),
680                                 RootWindowOfScreen (XtScreen (switch_data->rc)),
681                                 &atom_names, &switch_count);
682
683          for (i = 0; i < switch_data->switch_count; i++)
684          {
685             if (atom_name == switch_data->atom_names[i])
686             {
687                if (switch_data->active_switch > i)
688                   switch_data->active_switch--;
689
690                XtFree (switch_data->switch_names[i]);
691                XtDestroyWidget (switch_data->buttons[i]);
692                XFree (switch_data->atom_names);
693                switch_data->atom_names = atom_names;
694                switch_data->switch_count = switch_count;
695
696                for (j = i; j < switch_data->switch_count; j++)
697                {
698                   switch_data->switch_names[j] = switch_data->switch_names[j+1];
699                   switch_data->buttons[j] = switch_data->buttons[j + 1];
700                }
701
702                break;
703             }
704          }
705
706
707          /*  When deleting a switch button, keep trying to decrease the  */
708          /*  row count to the requested value.                           */
709
710          if (panel.switch_row_count > (int)
711               (switch_data->element_values[SWITCH_NUMBER_OF_ROWS].parsed_value))
712          {
713             button_width = XtWidth (switch_data->buttons[0]);
714             XtSetArg (al[0], XmNspacing, &button_spacing);
715             XtGetValues (switch_data->rc, al, 1);
716
717             if ((int)(screen_width - (width + button_width + button_spacing)) >
718                                                                               0)
719             {
720                panel.switch_row_count--;
721                XtSetArg (al[0], XmNnumColumns, panel.switch_row_count);
722                XtSetValues (switch_data->rc, al, 1);
723             }
724          }
725
726          WorkspaceAdjustPanelPosition (x, y, width, height);
727
728       }
729       break;
730
731          
732       /*  Loop through the current set of atom names, comparing        */
733       /*  them with the new atom.  When a match is found, reset the    */
734       /*  the switch name to the new one and update the button label.  */
735
736       case DtWSM_REASON_TITLE:
737       {
738          XmString toggle_string;
739
740          Arg al[2];
741          int i;
742
743          for (i = 0; i < switch_data->switch_count; i++)
744          {
745             if (atom_name == switch_data->atom_names[i])
746             {
747                switch_data->switch_names[i] = 
748                   XtNewString (workspace_info->pchTitle);
749
750                toggle_string =
751                   XmStringCreateLocalized (workspace_info->pchTitle);
752
753                XtSetArg (al[0], XmNstring, toggle_string);
754                XtSetValues (switch_data->buttons[i], al, 1);
755                XmStringFree (toggle_string);
756
757                XtSetArg (al[0], XmNiconName, workspace_info->pchTitle);
758                XtSetArg (al[1], XmNtitle, workspace_info->pchTitle);
759                XtSetValues (panel.shell, al, 2);
760
761                break;
762             }
763          }
764       }
765       break;
766
767
768       /*  Loop through the set of switch atom names to find the one  */
769       /*  that is now active.  Unset the old workspace button and    */
770       /*  set the new one referenced by the atom.                    */
771
772       case DtWSM_REASON_CURRENT:
773       {
774          int i;
775          Arg al[2];
776    
777          for (i = 0; i < switch_data->switch_count; i++)
778          {
779             if (switch_data->atom_names[i] == atom_name)
780             {
781                XtSetArg (al[0], XmNiconName, switch_data->switch_names[i]); 
782                XtSetArg (al[1], XmNtitle, switch_data->switch_names[i]);
783                XtSetValues (panel.shell, al, 2);
784
785                _DtIconSetState (switch_data->buttons[switch_data->active_switch], False, False);
786                switch_data->active_switch = i;
787                _DtIconSetState (switch_data->buttons[switch_data->active_switch], True, False);
788                break;
789             }
790          }
791       }
792       break;
793    }
794
795    DtWsmFreeWorkspaceInfo (workspace_info);
796
797  
798
799
800  
801 /************************************************************************
802  *
803  *  SwitchButtonCB
804  *      Process callbacks on the switch buttons.  This function cause
805  *      either the workspace switch to occur or for the switch button
806  *      label to become editable.
807  *
808  ************************************************************************/
809
810
811 void
812 SwitchButtonCB (Widget    w,
813                 XtPointer client_data,
814                 XtPointer call_data) 
815
816
817 {
818    DtControlCallbackStruct * callback = (DtControlCallbackStruct *) call_data;
819    XEvent * event = callback->event;
820
821    Widget        switch_button = w;
822    Widget        old_switch_button;
823    BoxData     * box_data;
824    SwitchData  * switch_data;
825    Atom          atom_name;
826
827    int i;
828    int ac;
829    Arg al[2];
830
831    if (callback->reason != XmCR_VALUE_CHANGED) return;
832    ac = 0;
833    XtSetArg (al[ac], XmNuserData, &box_data);   ac++;
834    XtGetValues (switch_button, al, ac);
835
836    switch_data = box_data->switch_data;
837    old_switch_button = switch_data->buttons[switch_data->active_switch];
838
839
840    /*   If the selection occured on a non-selected button, find the atom  */
841    /*   representing the workspace name of the button that was selected   */
842    /*   and use it to call the workspace manager API to switch the        */
843    /*   workspace.  The indication on the buttons occurs out of the       */
844    /*   called from the workspace manager API.                            */
845    /*                                                                     */
846    /*  If the selection occured on the current button, set up the name    */
847    /*  change editing functions.                                          */
848    
849    if (switch_button != old_switch_button)
850    {   
851
852       /*  See if the workspace name is being edited.  If so, call the  */
853       /*  callback function to accept the changes.                     */
854    
855       if (XtIsManaged (box_data->switch_edit))
856       {
857          Widget edit_switch_button;
858             
859          XtSetArg (al[0], XmNuserData, &edit_switch_button);
860          XtGetValues (box_data->switch_edit, al, 1);
861          SwitchRenameCB (box_data->switch_edit, 
862                          (XtPointer) edit_switch_button, (XtPointer) NULL);
863
864          XmProcessTraversal (w, XmTRAVERSE_CURRENT);
865       }
866
867
868       if (event->xany.type == ButtonRelease)
869          switch_data->time_stamp = event->xbutton.time;
870
871       for (i = 0; i < switch_data->switch_count; i++)
872       {
873          if (switch_button == switch_data->buttons[i])
874          {
875             XtSetArg (al[0], XmNiconName, switch_data->switch_names[i]);
876             XtSetArg (al[1], XmNtitle, switch_data->switch_names[i]);
877             XtSetValues (panel.shell, al, 2);
878
879             DtWsmSetCurrentWorkspace (XtParent (switch_button),
880                                       switch_data->atom_names[i]);
881             break;
882          }
883       }
884
885       _DtIconSetState (old_switch_button, False, False);
886    }
887    else
888    {
889       /* Don't do anything on double click */
890
891       if (event->xany.type == ButtonRelease)
892       {
893          if ((event->xbutton.time - switch_data->time_stamp) >
894              XtGetMultiClickTime(XtDisplay(panel.shell)))
895          {
896             switch_data->time_stamp = event->xbutton.time;
897             SwitchRenameLabel (w, box_data);
898          }
899       }
900
901       _DtIconSetState (w, True, False);
902    }
903 }
904
905
906
907
908 /************************************************************************
909  *
910  *  SwitchRenameCancel
911  *        This is the XtActionProc that gets called when a user types
912  *        escape in a text widget which has this translation tied to it.
913  *
914  ***********************************************************************/
915
916
917 static void
918 SwitchRenameCancel (Widget      w,
919                     XEvent    * event,
920                     String    * params,
921                     Cardinal  * num_params)
922
923
924 {
925    Widget switch_button;
926    Arg al[1];
927  
928
929    /*  Extract the toggle button from the text field's user data  */
930
931    XtSetArg (al[0], XmNuserData, &switch_button);
932    XtGetValues (w, al, 1);
933    
934
935    /*  Remove the callbacks to eliminate double processing  */
936
937    XtRemoveAllCallbacks (w, XmNactivateCallback);
938
939
940    /*  Unmanage the text widget, set the traversal to the button and exit  */
941
942    XtUnmanageChild (w);
943    XmProcessTraversal (switch_button, XmTRAVERSE_CURRENT);
944 }
945
946
947
948
949 /************************************************************************
950  *
951  *  SwitchRenameCB
952  *      Process callbacks on the text field when a switch name is
953  *      being edited.
954  *
955  ************************************************************************/
956
957
958 static void
959 SwitchRenameCB (Widget    w,
960                 XtPointer client_data,
961                 XtPointer call_data) 
962
963
964 {
965    Widget   switch_button = (Widget) client_data;
966    char   * edit_string;
967
968    BoxData    * box_data;
969    SwitchData * switch_data;
970
971    Boolean valid;
972    int     current_switch;
973    int     i;
974          
975    int ac;
976    Arg al[2];
977
978    /*  Remove the callbacks to eliminate double processing  */
979
980    XtRemoveCallback (w, XmNactivateCallback, 
981                      SwitchRenameCB, (XtPointer) client_data);
982
983
984    /*  If this callback has been called and the text widget is already  */
985    /*  unmanaged, it means that the escape key was pressed, so return   */
986    
987    if (XtIsManaged(w) == False) return;
988
989
990    /*  Process the two reasons this callback is invoked.  A <Return>  */
991    /*  key has been pressed or the focus is being moved.  Accept the  */
992    /*  new name for both conditions.                                  */
993
994    ac = 0;
995    XtSetArg (al[ac], XmNuserData, &box_data);   ac++;
996    XtGetValues (switch_button, al, ac);
997
998    switch_data = box_data->switch_data;
999
1000    for (i = 0; i < switch_data->switch_count; i++)
1001       if (switch_data->buttons[i] == switch_button)
1002          current_switch = i;
1003
1004
1005    /*  Get the new name from the text field  */
1006
1007    edit_string = (char *) XmTextFieldGetString (w);
1008
1009
1010    /*  Verify that title is valid and unique and if so, validate     */
1011    /*  uniqueness and then change the toggle and workspace internal  */
1012    /*  information.                                                  */
1013
1014    valid = True;
1015
1016    _DtStripSpaces (edit_string);
1017
1018    if (strlen (edit_string) == 0)
1019       valid = False;
1020    else
1021    {
1022       for (i = 0; i < switch_data->switch_count; i++)
1023       {
1024          if (strcmp (switch_data->switch_names[i], edit_string) == 0)
1025          {
1026             if (i == current_switch)
1027             {
1028                XtUnmanageChild (w);
1029                XmProcessTraversal (switch_button, XmTRAVERSE_CURRENT);
1030                XtFree (edit_string);
1031                return;
1032             }
1033             else
1034             {
1035                valid = False;
1036                break;
1037             }
1038          }
1039       }
1040    }
1041
1042
1043    /*  If the title is not valid, post and error dialog and  */
1044    /*  then leave the text field active to allow reediting.  */
1045    /*  Otherwise, change the title.                          */
1046
1047    if (!valid)
1048    {
1049       char * s1;
1050       char * s2;
1051
1052       s1 = FPGETMESSAGE (86, 1, "Workspace Manager - Rename Error");
1053       s1 = XtNewString (s1);
1054       s2 = FPGETMESSAGE (86, 2, "Invalid or duplicate workspace name"),
1055       s2 = XtNewString (s2);
1056
1057       _DtMessage (XtParent (w), s1, s2, NULL, NULL);
1058
1059       XtFree (s1);
1060       XtFree (s2);
1061    }
1062    else
1063       _DtWsmSetWorkspaceTitle (panel.shell, 
1064                                switch_data->atom_names[current_switch],
1065                                edit_string);
1066
1067
1068    /*  Unmanage the text field and exit  */
1069
1070    XtFree (edit_string);
1071    XtUnmanageChild (w);
1072 }
1073
1074
1075
1076
1077 /************************************************************************
1078  *
1079  *  SwitchRenameLabel
1080  *      Set up the text field and callbacks needed for renaming a 
1081  *      workspace.
1082  *
1083  ************************************************************************/
1084
1085
1086 void
1087 SwitchRenameLabel (Widget    switch_button,
1088                    BoxData * box_data)
1089
1090
1091 {
1092    Widget switch_edit = box_data->switch_edit;
1093
1094    static Boolean first = True;
1095
1096    XmString   toggle_string;
1097    Position   toggle_x;
1098    Position   toggle_y;
1099    Dimension  toggle_width;
1100    Dimension  toggle_height;
1101    XmFontList toggle_font_list;
1102    Pixel      toggle_background;
1103
1104    Position  switch_rc_x;
1105    Position  switch_rc_y;
1106
1107    char * edit_string;
1108
1109    XtTranslations trans_table;
1110
1111    int    ac;
1112    Arg    al[15];
1113
1114
1115    /*  Add the additional actions needed by the panel and  */
1116    /*  set up translations in main edit widget             */
1117
1118    if (first)
1119    {
1120       first = False;
1121
1122       XtAppAddActions(XtWidgetToApplicationContext(panel.shell),action_table,1);
1123       trans_table = XtParseTranslationTable (translations_escape);
1124       XtOverrideTranslations (switch_edit, trans_table);
1125    }
1126
1127
1128    /*  Extract the label and toggle position  */
1129
1130    ac = 0;
1131    XtSetArg (al[ac], XmNx, &toggle_x);   ac++;
1132    XtSetArg (al[ac], XmNy, &toggle_y);   ac++;
1133    XtSetArg (al[ac], XmNwidth, &toggle_width);   ac++;
1134    XtSetArg (al[ac], XmNheight, &toggle_height);   ac++;
1135    XtSetArg (al[ac], XmNstring, &toggle_string);   ac++;
1136    XtSetArg (al[ac], XmNfontList, &toggle_font_list);   ac++;
1137    XtGetValues (switch_button, al, ac);
1138
1139
1140    /*  Extract the switch_rc's position  */
1141
1142    switch_rc_x = XtX (XtParent (switch_button));
1143    switch_rc_y = XtY (XtParent (switch_button));
1144
1145
1146    /*  Convert the xm string into a char string for editing  and  */
1147    /*  then create the text widget to perform the name editing.   */
1148
1149    if ((edit_string =
1150         (char *)_XmStringUngenerate(toggle_string, NULL,
1151                                     XmCHARSET_TEXT, XmCHARSET_TEXT))
1152        != (char *)NULL)
1153    {
1154
1155       /*  Set the switch editing field to the new resource set  */
1156
1157       ac = 0;
1158       XtSetArg (al[ac], XmNleftOffset, toggle_x + switch_rc_x);   ac++;
1159       XtSetArg (al[ac], XmNleftAttachment, XmATTACH_FORM);   ac++;
1160       XtSetArg (al[ac], XmNtopOffset, toggle_y + switch_rc_y);   ac++;
1161       XtSetArg (al[ac], XmNtopAttachment, XmATTACH_FORM);   ac++;
1162       XtSetArg (al[ac], XmNmarginWidth, 4);   ac++;
1163       XtSetArg (al[ac], XmNmarginHeight, 0);   ac++;
1164       XtSetArg (al[ac], XmNfontList, toggle_font_list);   ac++;
1165       XtSetArg (al[ac], XmNhighlightThickness, 1);   ac++;
1166       XtSetArg (al[ac], XmNvalue, edit_string);   ac++;
1167       XtSetArg (al[ac], XmNuserData, switch_button);   ac++;
1168
1169       XtSetValues (switch_edit, al, ac);
1170
1171       XtFree(edit_string);
1172
1173       ac = 0;
1174       XtSetArg (al[ac], XmNcursorPosition, 
1175                 XmTextFieldGetLastPosition (switch_edit));   ac++;
1176       XtSetArg (al[ac], XmNwidth, toggle_width);   ac++;
1177       XtSetArg (al[ac], XmNheight, toggle_height);   ac++;
1178       XtSetValues (switch_edit, al, ac);
1179
1180
1181       /*  Add the callbacks for the text input processing  */
1182
1183       XtAddCallback (switch_edit, XmNactivateCallback, 
1184                      SwitchRenameCB, (XtPointer) switch_button);
1185
1186       XtManageChild (switch_edit);
1187
1188       XRaiseWindow (XtDisplay (switch_edit), XtWindow (switch_edit));
1189       XSetInputFocus (XtDisplay (switch_edit), XtWindow (panel.shell),
1190                       RevertToParent, CurrentTime);
1191
1192       XmProcessTraversal (switch_edit, XmTRAVERSE_CURRENT);
1193    }
1194
1195    XmStringFree (toggle_string);
1196 }
1197
1198
1199
1200
1201 /************************************************************************
1202  ************************************************************************
1203  
1204     The next block of functions are used for the push and drop callbacks
1205     on all of the panel controls.
1206     
1207  ************************************************************************    
1208  ************************************************************************/
1209
1210
1211
1212
1213 /************************************************************************
1214  *
1215  *  CheckControlTypeFile
1216  *      Check the control if it is of type "file" that the file exists
1217  *      before performing a push or drop action.
1218  *
1219  *  Inputs: control_data - the control whose file type and status are
1220  *                         to be checked.
1221  *
1222  ************************************************************************/
1223
1224
1225 Boolean
1226 CheckControlTypeFile (ControlData * control_data)
1227
1228
1229 {
1230    struct   stat stat_info;
1231    char   * file_name;
1232    char   * title;
1233    char   * msg;
1234    char   * message;
1235    
1236
1237    if ((int) control_data->element_values[CONTROL_TYPE].parsed_value != CONTROL_FILE)
1238       return (True);
1239       
1240    file_name = 
1241       (char *) control_data->element_values[CONTROL_FILE_NAME].parsed_value;
1242
1243    if (lstat (file_name, &stat_info) == 0)
1244       return (True);
1245
1246
1247    /*  Display an error dialog because the file cannot be found  */
1248
1249    title = FPGETMESSAGE (86, 9, "Workspace Manager - Icon Action Error");
1250    title = XtNewString (title);
1251
1252    msg = FPGETMESSAGE (86, 7, "Cannot find the file");
1253    message = XtMalloc (strlen (msg) + strlen (file_name) + 2);
1254    sprintf (message, "%s %s", msg, file_name);
1255
1256    _DtMessage (panel.shell, title, message, NULL, NULL);
1257
1258    XtFree (title);
1259    XtFree (message);        
1260
1261    return (False);   
1262 }
1263
1264
1265
1266 /************************************************************************
1267  *
1268  *  FreeFunctionArg
1269  *      Free the function argument
1270  *
1271  ************************************************************************/
1272
1273 static void
1274 FreeFunctionArg (
1275     WmFunction wmFunc,
1276     void *pArg)
1277 {
1278     if (pArg != NULL)
1279     {
1280         if (wmFunc == F_Action)
1281         {
1282             WmActionArg *pAP = (WmActionArg *) pArg;
1283
1284             if (pAP->aap != NULL)
1285             {
1286                 int i;
1287
1288                 for (i=0; i < pAP->numArgs; i++)
1289                 {
1290                     if (pAP->aap[i].u.file.name != NULL)
1291                         XtFree ((char *) pAP->aap[i].u.file.name);
1292                 }
1293                 XtFree ((char *) pAP->aap);
1294             }
1295
1296             if (pAP->actionName != NULL)
1297                 XtFree ((char *) pAP->actionName);
1298
1299             if (pAP->szExecParms != NULL)
1300                 XtFree ((char *) pAP->szExecParms);
1301
1302         }
1303
1304         XtFree ((char *) pArg);
1305     }
1306 }
1307
1308 Boolean
1309 CheckOtherMonitorsOn(SubpanelData * subpanel_data)
1310 {
1311    int i;
1312    ControlData * control_data;
1313    Boolean m_state;
1314
1315    for (i = -1; i < subpanel_data->control_data_count; i++)
1316    {
1317      if (i == -1)
1318      {
1319        m_state = _DtControlGetMonitorState(subpanel_data->main_panel_icon_copy);
1320      }
1321      else
1322      {
1323        control_data = subpanel_data->control_data[i];
1324        m_state = _DtControlGetMonitorState(control_data->icon);
1325      }
1326         
1327      if (m_state == DtMONITOR_ON) return True;
1328    }
1329
1330    return False;
1331 }
1332
1333
1334 /************************************************************************
1335  *
1336  *  PushCB
1337  *      Process the callback on a control.
1338  *
1339  ************************************************************************/
1340
1341 void
1342 PushCB (Widget    w,
1343         XtPointer client_data,
1344         XtPointer call_data) 
1345
1346 {
1347    int control_behavior;
1348
1349    DtControlCallbackStruct * callback = (DtControlCallbackStruct *) call_data;
1350    XEvent * event = callback->event;
1351    ControlData * control_data = (ControlData *) client_data;
1352    int           control_type;
1353
1354    PanelActionData * push_action;
1355    Boolean           push_recall;
1356    Boolean           unpost_subpanel = True;
1357
1358    BoxData      * box_data;
1359    SubpanelData * subpanel_data;
1360    ControlData  * main_control_data;
1361
1362    char m_state;
1363
1364    Widget * pWid;
1365
1366    Widget monitor_icon;
1367    Arg    al[1];      
1368
1369    int i, j;
1370    
1371
1372    control_behavior = (int) (panel.element_values[PANEL_CONTROL_BEHAVIOR].parsed_value);
1373
1374
1375    /*  See if the workspace name is being edited.  If so, call the  */
1376    /*  callback function to accept the changes.                     */
1377    
1378    for (i = 0; i < panel.box_data_count; i++)
1379    {
1380       if (panel.box_data[i]->switch_edit != NULL)
1381       {
1382          if (XtIsManaged (panel.box_data[i]->switch_edit))
1383          {
1384             Widget switch_button;
1385             
1386             XtSetArg (al[0], XmNuserData, &switch_button);
1387             XtGetValues (panel.box_data[i]->switch_edit, al, 1);
1388             SwitchRenameCB (panel.box_data[i]->switch_edit, 
1389                             (XtPointer) switch_button, (XtPointer) NULL);
1390             XmProcessTraversal (w, XmTRAVERSE_CURRENT);
1391             break;
1392          }
1393       }
1394    }
1395
1396
1397    /*  See if the control action occurred out of a subpanel.  If so,  */
1398    /*  get the subpanel and set the main control data.                */
1399
1400    if (control_data->parent_type == SUBPANEL)
1401    {
1402       subpanel_data = (SubpanelData *) control_data->parent_data;
1403       main_control_data = subpanel_data->parent_control_data;
1404
1405       /*  This control may have been toggled from the subpanel.  If  */
1406       /*  so, make sure the subpanel is not reposted.                */
1407
1408
1409       if (XtParent (w) != subpanel_data->form)
1410          unpost_subpanel = False;
1411    }
1412    else
1413    {
1414       /*  The control may be the main panel icon copy.  If so, find  */
1415       /*  the subpanel that contains it a set the subpanel data      */
1416
1417       subpanel_data = NULL;
1418
1419       for (i = 0; i < panel.box_data_count; i++)
1420       {
1421          for (j = 0; j < panel.box_data[i]->control_data_count; j++)
1422          {
1423             ControlData * box_control;
1424
1425             box_control = panel.box_data[i]->control_data[j];
1426
1427             if (box_control->subpanel_data != NULL &&
1428                 box_control->subpanel_data->main_panel_icon_copy == w)
1429             {
1430                subpanel_data = box_control->subpanel_data;
1431                main_control_data = subpanel_data->parent_control_data;
1432                break;
1433             }
1434          }
1435          if (subpanel_data != NULL)
1436             break;
1437       }
1438    }
1439
1440
1441    /*  If the input occurred out of a subpanel, check to see if  */
1442    /*  the input was an escape key.  If so, unpost the subpanel  */
1443    /*  and return.                                               */
1444
1445    if (subpanel_data != NULL && event != NULL)
1446    {
1447       if (event->xany.type == KeyPress)
1448       {
1449          int count;
1450          char buffer[10];
1451          int bufsize = 10;
1452          KeySym keysym;
1453          XComposeStatus compose;
1454          static Boolean first = True;
1455
1456          count = XLookupString ((XKeyEvent *)event, buffer, bufsize,
1457                                 &keysym, &compose);
1458
1459          if (keysym == XK_Escape)
1460          {
1461             if (first)
1462             {
1463                ArrowCB (main_control_data->arrow,
1464                         (XtPointer)main_control_data, (XtPointer)NULL);
1465                first = False;
1466             }
1467             else
1468                first = True;
1469
1470             return;
1471          }
1472       }
1473    }
1474
1475
1476    /*  This function handles four callback reasons.  Two of them, */
1477    /*  START and STOP show and remove an hour glass cursor.       */
1478    /*  MONITOR modifies subpanel visuals when a file change is    */
1479    /*  detected.  ACTIVATE/DEFAULT_ACTION handle the activation   */
1480    /*  of a control.                                              */
1481
1482    if (callback->reason == XmCR_BUSY_START)
1483    {
1484
1485       XDefineCursor (XtDisplay (panel.shell), XtWindow (panel.shell),
1486                      panel.busy_cursor);
1487
1488       for (i = 0, pWid = M_PopupList (panel.shell);
1489            i < M_NumPopups (panel.shell); i++)
1490          XDefineCursor (XtDisplay (panel.shell), XtWindow (pWid[i]),
1491                         panel.busy_cursor);
1492       
1493    }
1494    else if (callback->reason == XmCR_BUSY_STOP)
1495    {
1496       XUndefineCursor (XtDisplay (panel.shell), XtWindow (panel.shell));
1497
1498       for (i = 0, pWid = M_PopupList (panel.shell);
1499            i < M_NumPopups (panel.shell); i++)
1500          XUndefineCursor (XtDisplay (panel.shell), XtWindow (pWid[i]));
1501       
1502    }
1503    else if (callback->reason == XmCR_MONITOR)
1504    {
1505       /*  For a monitor file, turn on the monitor indicator for  */
1506       /*  the subpanel control and turn on the arrow to the      */
1507       /*  highlighted arrow of the subpanel.                     */
1508       
1509       if (subpanel_data != NULL)
1510       {
1511          monitor_icon = control_data->indicator;
1512
1513          m_state = _DtControlGetMonitorState(w);
1514
1515          if (m_state == DtMONITOR_ON)
1516             XtSetArg (al[0], XmNimageName, indicator_on_image);
1517          else /* DtMONITOR_OFF */
1518             XtSetArg (al[0], XmNimageName, indicator_off_image);
1519
1520          XtSetValues (monitor_icon, al, 1);
1521
1522          if (XtIsManaged (subpanel_data->shell))
1523          {
1524             if (m_state == DtMONITOR_ON)
1525             {
1526                XtSetArg (al[0], XmNimageName, unpost_monitor_arrow_image);
1527                XtSetValues (main_control_data->arrow, al, 1);
1528             }
1529             else
1530             {
1531                if (!CheckOtherMonitorsOn(subpanel_data))
1532                {
1533                   XtSetArg (al[0], XmNimageName, unpost_arrow_image);
1534                   XtSetValues (main_control_data->arrow, al, 1);
1535                }
1536             }
1537          }
1538          else
1539          {
1540             if (m_state == DtMONITOR_ON)
1541             {
1542                XtSetArg (al[0], XmNimageName, post_monitor_arrow_image);
1543                XtSetValues (main_control_data->arrow, al, 1);
1544             }
1545             else
1546             {
1547                if (!CheckOtherMonitorsOn(subpanel_data))
1548                {
1549                   XtSetArg (al[0], XmNimageName, post_arrow_image);
1550                   XtSetValues (main_control_data->arrow, al, 1);
1551                }
1552             }
1553          }
1554
1555       }
1556    }
1557    else if ((control_behavior == DOUBLE_CLICK && 
1558             callback->reason == XmCR_DEFAULT_ACTION) ||
1559             (control_behavior == SINGLE_CLICK &&
1560              (callback->reason == XmCR_DEFAULT_ACTION || 
1561               callback->reason == XmCR_SINGLE_SELECT)))
1562    {
1563       control_type = (int) (control_data->element_values[CONTROL_TYPE].parsed_value);
1564       push_action = (PanelActionData *) (control_data->element_values[CONTROL_PUSH_ACTION].parsed_value);
1565       push_recall = (Boolean) (control_data->element_values[CONTROL_PUSH_RECALL].parsed_value);
1566
1567       switch (control_type)
1568       {
1569          case CONTROL_CLIENT:
1570          case CONTROL_ICON:
1571          case CONTROL_FILE:
1572          case CONTROL_DATE:
1573          {
1574       
1575             /*  Turn off the subpanel control monitor indicator  */
1576
1577             if ((char) control_data->element_values[CONTROL_MONITOR_TYPE].
1578                        parsed_value != MONITOR_NONE)
1579             {
1580                if (subpanel_data != NULL)
1581                {
1582                   monitor_icon = control_data->indicator;
1583                   XtSetArg (al[0], XmNimageName, indicator_off_image);
1584                   XtSetValues (monitor_icon, al, 1);
1585                }
1586             }
1587
1588
1589             if (CheckControlTypeFile (control_data) && push_action != NULL)
1590             {
1591                _DtControlDoPushAnimation (w);   
1592
1593                if (push_recall == False)
1594                {
1595                   /*  If the control is of type file, build and object  */
1596                   /*  list that contains the host and file name to      */
1597                   /*  pass to the invokation.                           */
1598                   
1599                   if (control_type == CONTROL_FILE && !control_data->is_action)
1600                   {
1601                      DtActionArg * aap;
1602
1603                      aap = (DtActionArg *) XtCalloc(1,sizeof(DtActionArg));
1604
1605                      aap->argClass = DtACTION_FILE;
1606
1607                      aap->u.file.name = (char *) control_data->
1608                                  element_values[CONTROL_FILE_NAME].parsed_value;
1609
1610                      DtActionInvoke (panel.shell, 
1611                                      push_action->action_name,
1612                                      aap, 1, NULL, NULL, NULL,
1613                                      1, NULL, NULL);
1614
1615                      XtFree ((char *) aap);
1616                   }
1617                   else
1618                   {
1619                      if (strcmp (push_action->action_name, "FPOnItemHelp") == 0)
1620                      {
1621                         WmDtHelpMode();
1622                         unpost_subpanel = False;
1623                      }
1624                      else
1625                      {
1626                         DtActionInvoke (panel.shell, 
1627                                         push_action->action_name,
1628                                         NULL, 0, NULL, NULL, NULL,
1629                                         1, NULL, NULL);
1630                      }
1631                   }
1632                }
1633                else
1634                {
1635                   WmFunction wm_func;
1636                   int        function_index;
1637                   String     func_arg = NULL;
1638                   String     s1, s1save;
1639                   char     * client_name;
1640                   char     * client_title;                
1641
1642                   WmGlobalData    * wm_global_data = (WmGlobalData *) panel.global_data;
1643                   ClientData      * wm_client_data = NULL;
1644                   WmPushRecallArg   push_argument;
1645
1646
1647                   /*  Parse out the function and arguments used by the  */
1648                   /*  window manager to invoke the client.              */
1649                   
1650                   s1save = s1 = XtNewString ("f.action");
1651
1652                   function_index = 
1653                     ParseWmFunction ((unsigned char **) &s1, CRS_ANY, &wm_func);
1654                   XtFree (s1save);
1655
1656
1657                   client_name = 
1658                      (char *) control_data->element_values[CONTROL_CLIENT_NAME].parsed_value;
1659
1660                   if (client_name == NULL)
1661                      client_name = 
1662                         (char *) control_data->element_values[CONTROL_LABEL].parsed_value;
1663
1664                   client_title = 
1665                      (char *) control_data->element_values[CONTROL_LABEL].parsed_value;
1666
1667                   if (control_type == CONTROL_FILE && ! control_data->is_action)
1668                   {
1669                      char * file_name;
1670
1671                      file_name = (char *) control_data->
1672                                           element_values[CONTROL_FILE_NAME].parsed_value;
1673
1674                      s1 = XtMalloc (strlen (push_action->action_name) + strlen (file_name) + 2);
1675                      strcpy (s1, push_action->action_name);
1676                      strcat (s1, " ");
1677                      strcat (s1, file_name);
1678                   }
1679                   else
1680                      s1 = XtNewString (push_action->action_name);
1681
1682                   ParseWmFunctionArg ((unsigned char **) &s1, function_index, 
1683                                       wm_func, (void **) &func_arg, 
1684                                       client_name, client_name);
1685
1686
1687                   /*  Set the push argument to the parsed data  */
1688                   
1689                   push_argument.ixReg = PushRecallGetData (client_name);
1690                   push_argument.wmFunc = wm_func;
1691                   push_argument.pArgs = func_arg;
1692
1693
1694                   /*  Get the window manager client data for the panel and  */
1695                   /*  call the push recall function to get the client run.  */
1696                   
1697                   if (subpanel_data != NULL)
1698                      XFindContext (wm_global_data->display, 
1699                                    XtWindow (subpanel_data->shell),
1700                                    wm_global_data->windowContextType,
1701                                    (XtPointer) &wm_client_data);
1702                   else
1703                      XFindContext (wm_global_data->display, 
1704                                    XtWindow (panel.shell),
1705                                    wm_global_data->windowContextType,
1706                                    (XtPointer) &wm_client_data);
1707
1708                   F_Push_Recall ((String) &push_argument, 
1709                                  wm_client_data, callback->event);
1710
1711                   FreeFunctionArg (wm_func, func_arg);
1712                   XtFree (s1);
1713                }
1714             }
1715          }
1716          break;
1717
1718
1719          case CONTROL_BLANK:
1720          case CONTROL_BUSY:
1721          case CONTROL_CLOCK:
1722             return;
1723          break;
1724       }
1725
1726
1727       /*  Call the unposting function and reset the arrow behavior if the  */
1728       /*  action occured out of a subpanel.                                */
1729
1730       if (subpanel_data != NULL && unpost_subpanel &&
1731           (Boolean) panel.element_values[PANEL_SUBPANEL_UNPOST].parsed_value &&
1732           subpanel_data->torn == False)
1733          ArrowCB (main_control_data->arrow,
1734                   (XtPointer)main_control_data, (XtPointer)NULL);
1735    }
1736 }
1737
1738
1739
1740
1741 /************************************************************************
1742  *
1743  *  DropCB
1744  *      Process the callback for drops on a control
1745  *
1746  ************************************************************************/
1747
1748
1749 void
1750 DropCB (Widget    w,
1751         XtPointer client_data,
1752         XtPointer call_data) 
1753
1754
1755 {
1756    PanelActionData * drop_action = (PanelActionData *) client_data;
1757    DtDndDropAnimateCallback animate_data =
1758                          (DtDndDropAnimateCallback) call_data;
1759
1760    ControlData    * control_data;
1761    Arg              al[1];
1762    int              i, j, k, l;
1763    DtActionArg    * aap;
1764    char           * save_name = NULL;
1765
1766    XtSetArg (al[0], XmNuserData, &control_data);
1767    XtGetValues (w, al, 1);
1768
1769    if (CheckControlTypeFile (control_data) &&
1770        (animate_data->dropData->protocol == DtDND_FILENAME_TRANSFER ||
1771         animate_data->dropData->protocol == DtDND_BUFFER_TRANSFER))
1772    {
1773       int numItems;
1774       int control_type =
1775          (int)control_data->element_values[CONTROL_TYPE].parsed_value;
1776       char * control_name =
1777          (char *)control_data->element_values[CONTROL_FILE_NAME].parsed_value;
1778       Boolean send_control_name = False;
1779
1780       _DtControlDoDropAnimation (w);
1781
1782       drop_action = (PanelActionData *) 
1783          control_data->element_values[CONTROL_DROP_ACTION].parsed_value;
1784
1785       if (control_data->operation == XmDROP_MOVE)
1786       {
1787          if (control_data->move_action)
1788          {
1789             save_name = drop_action->action_name;
1790             drop_action->action_name = control_data->move_action;
1791          }
1792       }
1793       else if (control_data->operation == XmDROP_COPY)
1794       {
1795          if (control_data->copy_action)
1796          {
1797             save_name = drop_action->action_name;
1798             drop_action->action_name = control_data->copy_action;
1799          }
1800       }
1801       else if (control_data->operation == XmDROP_LINK)
1802       {
1803          if (control_data->link_action)
1804          {
1805             save_name = drop_action->action_name;
1806             drop_action->action_name = control_data->link_action;
1807          }
1808       }
1809
1810   
1811       numItems = animate_data->dropData->numItems;
1812   
1813       if ((control_type == CONTROL_FILE) &&
1814           (!control_data->is_action) &&
1815           (strcmp(control_name, drop_action->action_name) != 0))
1816       {
1817         ++numItems;
1818         send_control_name = True;
1819       }
1820
1821       if (animate_data->dropData->protocol == DtDND_FILENAME_TRANSFER)
1822       {
1823          char ** file_list = animate_data->dropData->data.files;
1824          int m = 0;
1825   
1826          aap = (DtActionArg *) XtCalloc (numItems, sizeof (DtActionArg));
1827   
1828          if (send_control_name)
1829          {
1830            aap[m].argClass = DtACTION_FILE;
1831            aap[m++].u.file.name = 
1832            (char *)control_data->element_values[CONTROL_FILE_NAME].parsed_value;
1833          }
1834   
1835          for (l = 0; m < numItems; l++, m++)
1836          {
1837              aap[m].argClass = DtACTION_FILE;
1838              aap[m].u.file.name = file_list[l];
1839          }
1840       }
1841       else if (animate_data->dropData->protocol == DtDND_BUFFER_TRANSFER)
1842       {
1843          DtDndBuffer * buf_list = animate_data->dropData->data.buffers;
1844          int m = 0;
1845   
1846          aap = (DtActionArg *) XtCalloc (numItems, sizeof (DtActionArg));
1847   
1848          if (send_control_name)
1849          {
1850            aap[m].argClass = DtACTION_FILE;
1851            aap[m++].u.file.name = 
1852            (char *)control_data->element_values[CONTROL_FILE_NAME].parsed_value;
1853          }
1854   
1855          for (l = 0; m < numItems; l++, m++)
1856          {
1857              aap[m].argClass = DtACTION_BUFFER;
1858              aap[m].u.buffer.bp = buf_list[l].bp;
1859              aap[m].u.buffer.size = buf_list[l].size;
1860              aap[m].u.buffer.name = buf_list[l].name;
1861          }
1862       }
1863       else
1864       {
1865          if (save_name != NULL)
1866             drop_action->action_name = save_name;
1867
1868          control_data->operation = NULL;
1869
1870          return;
1871       }
1872        
1873       DtActionInvoke (w, drop_action->action_name, aap, numItems,
1874                      NULL, NULL, NULL, 1, NULL, NULL);
1875
1876       XtFree((char *) aap);
1877
1878       if (save_name != NULL)
1879          drop_action->action_name = save_name;
1880
1881       control_data->operation = NULL;
1882    }
1883 }
1884
1885
1886
1887
1888 /************************************************************************
1889  *
1890  *  TransferDropCB
1891  *      Process the callback for drops on a control
1892  *
1893  ************************************************************************/
1894
1895
1896 void
1897 TransferDropCB (Widget    w,
1898                 XtPointer client_data,
1899                 XtPointer call_data) 
1900
1901
1902 {
1903    DtDndTransferCallbackStruct * transfer_data =
1904                          (DtDndTransferCallbackStruct *) call_data;
1905    ControlData * control_data;
1906    Arg           al[1];
1907
1908
1909    /* Currently only accepts FILE drops */
1910
1911    if (transfer_data->dropData->protocol == DtDND_FILENAME_TRANSFER ||
1912        transfer_data->dropData->protocol == DtDND_BUFFER_TRANSFER)
1913    {
1914       transfer_data->status = DtDND_SUCCESS;
1915
1916       XtSetArg (al[0], XmNuserData, &control_data);
1917       XtGetValues (w, al, 1);
1918
1919       control_data->operation = transfer_data->operation;
1920
1921    }
1922    else
1923       transfer_data->status = DtDND_FAILURE;
1924
1925    transfer_data->completeMove = False;
1926 }
1927
1928
1929
1930 /************************************************************************
1931  ************************************************************************
1932  
1933     This block of functions handle the processing of subpanel torn-off
1934     behavior.  Default behavior for a subpanel is to unpost when a 
1935     control is selected.  This changes to sticky when the subpanel is torn.
1936     
1937  ************************************************************************
1938  ************************************************************************/
1939
1940
1941 /************************************************************************
1942  *
1943  *  SubpanelUnmapCB
1944  *      Process the callback on the subpanel unposting initiated through
1945  *      the window manager close menu item.
1946  *
1947  ************************************************************************/
1948
1949
1950 void
1951 SubpanelUnmapCB (Widget    w,
1952                  XtPointer client_data,
1953                  XtPointer call_data) 
1954
1955
1956 {
1957    ControlData  * main_control_data = (ControlData *) client_data;
1958    SubpanelData * subpanel_data = main_control_data->subpanel_data;
1959
1960    Arg  al[1];
1961    int  ac;
1962
1963
1964    ac = 0;
1965    XtSetArg (al[ac], XmNimageName, post_arrow_image);   ac++;
1966    XtSetValues (main_control_data->arrow, al, ac);
1967
1968    XtUnmanageChild (subpanel_data->shell);
1969    subpanel_data->torn = False;
1970
1971
1972    /*  Remove the event handler from the subpanel  */
1973
1974    XtRemoveEventHandler (subpanel_data->shell, StructureNotifyMask, False,
1975                          (XtEventHandler) SubpanelTornEventHandler,
1976                          (XtPointer) main_control_data);
1977
1978
1979    /*  Reset the active traversal control for the front panel  */
1980    /*  We should not have to do this but for unknown reasons,  */
1981    /*  the traversal highlight is getting lost.                */
1982    
1983    XmProcessTraversal (panel.shell, XmTRAVERSE_NEXT);
1984    XmProcessTraversal (panel.shell, XmTRAVERSE_PREV);
1985 }
1986
1987
1988
1989
1990 /************************************************************************
1991  *
1992  *  SubpanelTornEventHandler
1993  *      Set a subpanel flag to change its posting behavior when it is
1994  *      torn off.
1995  *
1996  ************************************************************************/
1997
1998 void
1999 SubpanelTornEventHandler (Widget      subpanel_shell,
2000                           XtPointer   client_data,
2001                           XEvent    * event,
2002                           Boolean   * continue_dispatch)
2003
2004 {
2005    ControlData  * main_control_data = (ControlData *) client_data;
2006    SubpanelData * subpanel_data = main_control_data->subpanel_data;
2007
2008
2009    if (subpanel_data->posted_x != 0 &&
2010        subpanel_data->posted_x != XtX (subpanel_data->shell))
2011        
2012       subpanel_data->torn = True;
2013    else
2014       subpanel_data->torn = False;
2015
2016    *continue_dispatch = True;
2017 }
2018
2019
2020
2021
2022
2023 /************************************************************************
2024  *
2025  *  StartHelpClient
2026  *      Start up the help manager to show the help topic
2027  *
2028  *  Inputs: widget - the widget for which help was requested
2029  *          help_volume - the help volume that contains the information
2030  *          help_topic - the specific help topic.
2031  *
2032  ************************************************************************/
2033
2034
2035 void StartHelpClient (Widget   widget,
2036                       char   * help_volume,
2037                       char   * help_topic)
2038
2039
2040 {
2041    /***** TEMPORARY - Add code to actually invoke the Help Client ****/  
2042
2043    WmDtDisplayTopicHelp (widget, help_volume, help_topic);
2044 }
2045
2046 /************************************************************************
2047  *
2048  *  InvokeHelp
2049  *      Invoke topic help if available otherwise invoke help string if
2050  *  available
2051  *
2052  ************************************************************************/
2053
2054
2055 void InvokeHelp (Widget widget,
2056                  char * help_topic,
2057                  char * help_volume,
2058                  char * help_string)
2059 {
2060
2061     if (help_volume == NULL)
2062        help_volume = FP_HELP_VOLUME;
2063
2064     if (help_topic != NULL)
2065     {
2066        if (strcmp (help_volume, FP_HELP_VOLUME) == 0)
2067           WmDtDisplayTopicHelp (widget, help_volume, help_topic);
2068        else
2069           StartHelpClient (widget, help_volume, help_topic);
2070     }
2071     else
2072     {
2073        if (help_string != NULL)
2074           WmDtDisplayStringHelp (widget, help_string);
2075     }
2076 }
2077
2078
2079 /************************************************************************
2080  *
2081  *  SubpanelTopicHelpCB
2082  *      Process the callback for help on the subpanel 
2083  *
2084  ************************************************************************/
2085
2086
2087 void SubpanelTopicHelpCB (Widget    widget,
2088                           XtPointer client_data,
2089                           XtPointer call_data)
2090
2091 {
2092     SubpanelData * subpanel_data = (SubpanelData *) client_data;
2093     char         * help_volume;
2094     char         * help_topic;
2095     char         * help_string;
2096
2097     help_volume =
2098       (char *) subpanel_data->element_values[SUBPANEL_HELP_VOLUME].parsed_value;
2099     help_topic =
2100       (char *) subpanel_data->element_values[SUBPANEL_HELP_TOPIC].parsed_value;
2101     help_string =
2102       (char *) subpanel_data->element_values[SUBPANEL_HELP_STRING].parsed_value;
2103
2104     InvokeHelp(widget, help_topic, help_volume, help_string);
2105
2106 } /* END OF FUNCTION SubpanelTopicHelpCB */
2107
2108
2109
2110
2111 /************************************************************************
2112  *
2113  *  SwitchTopicHelpCB
2114  *      Process the callback for help on the switch 
2115  *
2116  ************************************************************************/
2117
2118
2119 void SwitchTopicHelpCB (Widget    widget,
2120                         XtPointer client_data,
2121                         XtPointer call_data)
2122
2123 {
2124     SwitchData * switch_data = (SwitchData *) client_data;
2125     char       * help_volume;
2126     char       * help_topic;
2127     char       * help_string;
2128
2129     help_volume =
2130          (char *) switch_data->element_values[SWITCH_HELP_VOLUME].parsed_value;
2131     help_topic =
2132          (char *) switch_data->element_values[SWITCH_HELP_TOPIC].parsed_value;
2133     help_string =
2134          (char *) switch_data->element_values[SWITCH_HELP_STRING].parsed_value;
2135
2136     InvokeHelp(widget, help_topic, help_volume, help_string);
2137
2138 } /* END OF FUNCTION SwitchTopicHelpCB */
2139
2140
2141
2142
2143 /************************************************************************
2144  *
2145  *  ControlTopicHelpCB
2146  *      Process the callback for help on the control 
2147  *
2148  *************************************************************************/ 
2149
2150
2151 void ControlTopicHelpCB (Widget    widget,
2152                          XtPointer client_data,
2153                          XtPointer call_data)
2154
2155
2156 {
2157     ControlData * control_data = (ControlData *) client_data;
2158     char        * help_volume;
2159     char        * help_topic;
2160     char        * help_string;
2161
2162     help_volume = 
2163         (char *) control_data->element_values[CONTROL_HELP_VOLUME].parsed_value;
2164     help_topic =
2165         (char *) control_data->element_values[CONTROL_HELP_TOPIC].parsed_value;
2166     help_string =
2167         (char *) control_data->element_values[CONTROL_HELP_STRING].parsed_value;
2168
2169     InvokeHelp(widget, help_topic, help_volume, help_string);
2170
2171 } /* END OF FUNCTION ControlTopicHelpCB */
2172
2173
2174
2175
2176 /************************************************************************
2177  *
2178  *  GeneralTopicHelpCB
2179  *      Process the callback for help on the control 
2180  *
2181  ************************************************************************/
2182
2183
2184 void GeneralTopicHelpCB (Widget    widget,
2185                          XtPointer client_data,
2186                          XtPointer call_data)
2187
2188
2189 {
2190     char * help_volume;
2191     char * help_topic;
2192
2193     help_volume = FP_HELP_VOLUME;
2194     help_topic = (char *) client_data;
2195
2196     WmDtDisplayTopicHelp (widget, help_volume, help_topic);
2197
2198 } /* END OF FUNCTION GeneralTopicHelpCB */
2199
2200
2201
2202
2203 /************************************************************************
2204  ************************************************************************
2205
2206     This block of functions handle the initialization and dynamic
2207     processing for the subpanel installation area.
2208
2209  ************************************************************************
2210  ************************************************************************/
2211
2212 /************************************************************************
2213  *
2214  *  GetValuesFromDataType
2215  *    Given and file type index and subpanel data, construct an element
2216  *    values array for a new control that is initialized to the attributes
2217  *    of the file type.
2218  *
2219  ************************************************************************/
2220
2221
2222 static void
2223 GetValuesFromDataType (char *          data_type,
2224                        char *          file_name,
2225                        SubpanelData  * subpanel_data,
2226                        ElementValue ** element_values)
2227
2228
2229 {
2230    char * ptr;
2231    int i;
2232
2233    *element_values = (ElementValue *) XtMalloc (sizeof(ElementValue) *
2234                                                        CONTROL_KEYWORD_COUNT);
2235
2236    for (i = 0; i < CONTROL_KEYWORD_COUNT; i++)
2237    {
2238       (*element_values)[i].use_default = True;
2239       (*element_values)[i].string_value = NULL;
2240       (*element_values)[i].parsed_value = NULL;
2241    }
2242
2243    (*element_values)[CONTROL_FILE_NAME].string_value = XtNewString (file_name);
2244
2245     ptr = (char *)strrchr(file_name, '/');
2246     ptr++;
2247
2248     (*element_values)[CONTROL_NAME].string_value = XtNewString(ptr);
2249     (*element_values)[CONTROL_TYPE].string_value = XtNewString("file");
2250     (*element_values)[CONTROL_CONTAINER_TYPE].string_value =
2251                                                 XtNewString("SUBPANEL");
2252     (*element_values)[CONTROL_CONTAINER_NAME].string_value =
2253                  XtNewString(subpanel_data->element_values[0].string_value);
2254     (*element_values)[CONTROL_POSITION_HINTS].string_value =
2255                                                 XtNewString("last");
2256
2257     InitializeControlFields (*element_values, data_type);
2258 }
2259
2260
2261
2262
2263 /************************************************************************
2264  *
2265  *  CustomizeDropCB
2266  *      Process the callback for the drop on the subpanel drop zone for
2267  *      dynamic customization
2268  *
2269  ************************************************************************/
2270
2271
2272 void
2273 CustomizeDropCB (Widget    w,
2274                  XtPointer client_data,
2275                  XtPointer call_data) 
2276
2277 {
2278    BoxData      * box_data;
2279    ControlData  * main_control_data;
2280    SubpanelData * subpanel_data;
2281    DtDndDropAnimateCallbackStruct * animate_data =
2282                          (DtDndDropAnimateCallbackStruct *) call_data;
2283
2284    ControlData  * control_data;
2285    ElementValue * element_values;
2286    char * data_type;
2287
2288    Boolean drop_of_fp;
2289    Boolean bad_control;
2290    Boolean control_monitor;
2291    int     position_hints;
2292    int     count;
2293
2294    char  * new_control_name;
2295    char  * control_name;
2296    Widget  attach_widget;
2297
2298    int i, j, k;
2299
2300    int     file_count;
2301    char ** file_list;
2302
2303    Arg al[4];
2304    int ac;
2305    
2306
2307    /*  If this is not a transfer drop, return  */
2308    
2309    if (animate_data->dropData->protocol != DtDND_FILENAME_TRANSFER)
2310       return;
2311
2312
2313    /*  Get the subpanel, box, and main control data  */
2314    
2315    XtSetArg (al[0], XmNuserData, &subpanel_data);
2316    XtGetValues (w, al, 1);
2317
2318    main_control_data = subpanel_data->parent_control_data;
2319    box_data = (BoxData *) main_control_data->parent_data;
2320    
2321    file_count = animate_data->dropData->numItems;
2322    file_list = animate_data->dropData->data.files;
2323
2324
2325    /*  Pop down the subpanel before creating the new control or  */
2326    /*  mucking with any of the old controls.                     */
2327
2328    if (subpanel_data->torn == False)
2329       XtUnmanageChild (subpanel_data->shell);        
2330
2331
2332    /*  Loop through the set of files (possibly more than one) that  */
2333    /*  have been dropped.                                           */
2334
2335    for (i = 0; i < file_count; i++)
2336    {
2337
2338       /*  Get the file type of the file and process as either  */
2339       /*  a "FrontPanel" file or a normal file type.           */
2340
2341       data_type = DtDtsFileToDataType (file_list[i]);
2342
2343       if (!strcmp (data_type, "FP"))
2344       {
2345          drop_of_fp = True;
2346          InitParse (file_list[i], &element_values);
2347
2348
2349          /*  Reset the values of the container name and type to this one  */
2350
2351          if (element_values[CONTROL_CONTAINER_NAME].use_default == False)
2352          {
2353             if (element_values[CONTROL_CONTAINER_NAME].parsed_value != NULL)
2354                XtFree (element_values[CONTROL_CONTAINER_NAME].parsed_value);
2355             if (element_values[CONTROL_CONTAINER_NAME].string_value != NULL)
2356                XtFree (element_values[CONTROL_CONTAINER_NAME].string_value);
2357          }
2358
2359          if (element_values[CONTROL_CONTAINER_TYPE].use_default == False)
2360          {
2361             if (element_values[CONTROL_CONTAINER_TYPE].string_value != NULL)
2362                XtFree (element_values[CONTROL_CONTAINER_TYPE].string_value);
2363          }
2364
2365          if (element_values[CONTROL_POSITION_HINTS].use_default == False)
2366          {
2367             if (element_values[CONTROL_POSITION_HINTS].string_value != NULL)
2368                XtFree (element_values[CONTROL_POSITION_HINTS].string_value);
2369          }
2370
2371          element_values[CONTROL_CONTAINER_NAME].use_default = False;
2372          element_values[CONTROL_CONTAINER_NAME].string_value = 
2373             XtNewString (subpanel_data->element_values[SUBPANEL_NAME].parsed_value);
2374          element_values[CONTROL_CONTAINER_NAME].parsed_value = 
2375             XtNewString (subpanel_data->element_values[SUBPANEL_NAME].parsed_value);
2376
2377          element_values[CONTROL_CONTAINER_TYPE].use_default = False;
2378          element_values[CONTROL_CONTAINER_TYPE].string_value = 
2379             XtNewString ("SUBPANEL");
2380          element_values[CONTROL_CONTAINER_TYPE].parsed_value =
2381             (char *) SUBPANEL;
2382
2383          element_values[CONTROL_POSITION_HINTS].use_default = False;
2384          element_values[CONTROL_POSITION_HINTS].string_value = 
2385             XtNewString ("last");
2386          element_values[CONTROL_POSITION_HINTS].parsed_value =
2387             (char *) 100;
2388       }
2389       else
2390       {
2391          drop_of_fp = False;
2392          GetValuesFromDataType (data_type, file_list[i], 
2393                                 subpanel_data, &element_values);
2394       }
2395
2396       DtDtsFreeDataType (data_type);
2397
2398
2399
2400       /*  Check for naming conflicts and if found, issue an error and   */
2401       /*  clean up.  Continue processing subsequent files even if this  */
2402       /*  one is not valid.                                             */
2403          
2404       new_control_name = (char *) element_values[CONTROL_NAME].parsed_value;
2405       bad_control = False;
2406
2407       for (j = 0; j < subpanel_data->control_data_count; j++)
2408       {
2409          control_name = (char *) subpanel_data->control_data[j]->
2410                                  element_values[CONTROL_NAME].parsed_value;
2411
2412          if (strcmp (control_name, new_control_name) == 0)
2413          {
2414             ControlData control_data;
2415             String title, del_ctrl, ctrl_name, del_msg, message;
2416          
2417
2418             /*  Display an error dialog for the unusable drop data  */
2419
2420             title = FPGETMESSAGE (86, 3, "Workspace Manager - Install Icon Error");
2421             title = XtNewString (title);
2422
2423             del_ctrl = FPGETMESSAGE (86, 4, "Install Icon:");
2424             del_ctrl = XtNewString (del_ctrl);
2425
2426             del_msg = FPGETMESSAGE (86, 8, "There is already an icon of this name.");
2427             del_msg = XtNewString (del_msg);
2428
2429             message = XtMalloc ((strlen(del_ctrl) + strlen(new_control_name) +
2430                                 strlen(del_msg) + 4));
2431             sprintf(message, "%s %s\n\n%s", del_ctrl, new_control_name, del_msg);
2432
2433             _DtMessage (panel.shell, title, message, NULL, NULL);
2434
2435             XtFree (title);         
2436             XtFree (del_ctrl);      
2437             XtFree (del_msg);       
2438             XtFree (message);       
2439
2440
2441             /*  Set up a temporary control data structure so that the   */
2442             /*  appropriate function can be used to free the allocated  */
2443             /*  element values.                                         */
2444
2445             control_data.element_values = element_values;
2446             RemoveEntry (&control_data, CONTROL);
2447          
2448             bad_control = True;
2449             break;
2450          }
2451       }
2452
2453       if (bad_control) continue;
2454
2455
2456       if ((int) element_values[CONTROL_MONITOR_TYPE].parsed_value != MONITOR_NONE)
2457          control_monitor = True;
2458       else
2459          control_monitor = False;
2460
2461
2462       position_hints = (int)element_values[CONTROL_POSITION_HINTS].parsed_value;
2463
2464
2465       /*  Initialize the subpanel layout and processing attributes.  */
2466
2467       if ((int) main_control_data->
2468            element_values[CONTROL_MONITOR_TYPE].parsed_value != MONITOR_NONE)
2469       {
2470          control_monitor = True;
2471       }
2472
2473
2474       for (j = 0; j < subpanel_data->control_data_count; j++)
2475       {
2476          if ((int) subpanel_data->control_data[j]->
2477              element_values[CONTROL_MONITOR_TYPE].parsed_value != MONITOR_NONE)
2478          {
2479             control_monitor = True;
2480             break;
2481          }
2482       }
2483
2484
2485       /*  If the new control is a montior, loop through the existing  */
2486       /*  control set a adjust the left offset resource to ensure     */
2487       /*  that they are all aligned properly.                         */
2488          
2489       if (control_monitor)
2490       {
2491          XtSetArg (al[0], XmNleftOffset, 20);
2492
2493          for (j = 0; j < subpanel_data->control_data_count; j++)
2494             XtSetValues (subpanel_data->control_data[j]->icon, al, 1);
2495
2496          if (subpanel_data->main_panel_icon_copy != NULL)
2497             XtSetValues (subpanel_data->main_panel_icon_copy, al, 1);
2498       }
2499
2500
2501       /*  Get the subpanel control data and position the element   */
2502       /*  values into the postion hints location.                  */
2503       /*  The remainder of the positioning code is set up to allow */
2504       /*  placement in non-last positions even though position is  */
2505       /*  forced to last.  This is here for future use.            */
2506
2507       subpanel_data->control_data_count++;
2508       count = subpanel_data->control_data_count;
2509
2510       subpanel_data->control_data = 
2511          (ControlData **) XtRealloc ((char *) subpanel_data->control_data, 
2512                                      sizeof (ControlData *) * count);
2513
2514       for (j = count - 2; j >= 0; j--)
2515       {
2516          if (position_hints >= 
2517              (int) subpanel_data->control_data[j]->element_values[CONTROL_POSITION_HINTS].parsed_value)
2518             break;
2519       }
2520
2521       j++;
2522          
2523       for (k = count - 1; k > j; k--)
2524          subpanel_data->control_data[k] = subpanel_data->control_data[k - 1];
2525
2526       subpanel_data->control_data[j] = control_data =
2527          (ControlData *) XtMalloc (sizeof (ControlData));
2528          
2529       control_data->element_values = element_values;
2530       control_data->parent_data = (XtPointer) subpanel_data;
2531       control_data->parent_type = SUBPANEL;
2532       control_data->subpanel_data = NULL;
2533       control_data->icon = NULL;
2534       control_data->arrow = NULL;
2535       control_data->arrow_separator = NULL;
2536       control_data->indicator = NULL;
2537       control_data->is_action = False;
2538       control_data->move_action = NULL;
2539       control_data->copy_action = NULL;
2540       control_data->link_action = NULL;
2541       control_data->operation = NULL;
2542
2543       AddControlActionList (control_data);
2544
2545
2546       if (j == 0 && subpanel_data->main_panel_icon_copy != NULL)
2547          attach_widget = subpanel_data->main_panel_icon_copy;
2548       else
2549          attach_widget = subpanel_data->control_data[j - 1]->icon;
2550
2551
2552       /*  Reattach the bottom control so the new bottom will appear  */
2553
2554       if (j == count - 1)
2555       {
2556          ac = 0;
2557          XtSetArg (al[ac], XmNbottomAttachment, XmATTACH_NONE);        ac++;
2558          XtSetArg (al[ac], XmNbottomOffset, 0);                        ac++;
2559          XtSetValues (attach_widget, al, ac);
2560       }
2561
2562
2563       SubpanelControlCreate (subpanel_data, main_control_data, 
2564                              control_data, attach_widget, False, 
2565                              control_monitor);
2566          
2567
2568       /*  Pad the bottom control */
2569
2570       if (j == count - 1)
2571       {
2572          ac = 0;
2573          XtSetArg (al[ac], XmNbottomAttachment, XmATTACH_FORM);        ac++;
2574          XtSetArg (al[ac], XmNbottomOffset, 5);                        ac++;
2575          XtSetValues (control_data->icon, al, ac);
2576       }
2577
2578       WriteControlComponentFile (control_data);
2579
2580    }
2581
2582
2583    /*  Pop the subpanel back up and return  */
2584
2585    if (subpanel_data->torn == False)
2586       ArrowCB (main_control_data->arrow,
2587                (XtPointer)main_control_data, (XtPointer)NULL);
2588 }
2589
2590
2591
2592
2593 /************************************************************************
2594  *
2595  *  CustomizeTransferDropCB
2596  *      Process the callback for drops on an install zone
2597  *
2598  ************************************************************************/
2599
2600
2601 void
2602 CustomizeTransferDropCB (Widget    w,
2603                 XtPointer client_data,
2604                 XtPointer call_data) 
2605
2606
2607 {
2608    DtDndTransferCallbackStruct * transfer_data =
2609                          (DtDndTransferCallbackStruct *) call_data;
2610
2611    /* Currently only accepts FILE drops */
2612
2613    if (transfer_data->dropData->protocol == DtDND_FILENAME_TRANSFER)
2614       transfer_data->status = DtDND_SUCCESS;
2615    else
2616       transfer_data->status = DtDND_FAILURE;
2617
2618    transfer_data->completeMove = False;
2619 }