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