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