cdesktopenv/cde/programs/dtwm/Callback.c

2623 lines
75 KiB
C

/*
* CDE - Common Desktop Environment
*
* Copyright (c) 1993-2012, The Open Group. All rights reserved.
*
* These libraries and programs are free software; you can
* redistribute them and/or modify them under the terms of the GNU
* Lesser General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* These libraries and programs are distributed in the hope that
* they will be useful, but WITHOUT ANY WARRANTY; without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU Lesser General Public License for more
* details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with these libraries and programs; if not, write
* to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
* Floor, Boston, MA 02110-1301 USA
*/
/*****************************************************************************
*
* File: Callback.c
*
* Project: CDE
*
* Description: This file contains the user interface behavior processing
* functions for the CDE front panel
*
* (c) Copyright 1993, 1994 Hewlett-Packard Company
* (c) Copyright 1993, 1994 International Business Machines Corp.
* (c) Copyright 1993, 1994 Sun Microsystems, Inc.
* (c) Copyright 1993, 1994 Novell, Inc.
*
****************************************************************************/
#include <stdint.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <Dt/DtP.h>
#include <Dt/DbReader.h>
#include "PanelSP.h"
#include <Dt/Control.h>
#include <Dt/ControlP.h>
#include <Dt/IconFile.h>
#include <Dt/Icon.h>
#include <Dt/Dnd.h>
#include <Dt/Dts.h>
#include <Dt/Action.h>
#include <Dt/DtNlUtils.h>
#include <Dt/WsmP.h>
#include <Dt/WsmM.h>
#include <Dt/MacrosP.h>
#include <Dt/SharedProcs.h>
#include <Xm/Form.h>
#include <Xm/ToggleBG.h>
#include <Xm/AtomMgr.h>
#include <Xm/TextF.h>
#include <X11/Xatom.h>
#include <X11/keysym.h>
#include "DataBaseLoad.h"
#include "UI.h"
#include "WmGlobal.h"
#include "WmHelp.h"
#include "WmResNames.h"
#include "WmResParse.h"
#include "WmFunction.h"
/************************************************************************
*
* External and static function declarations.
*
************************************************************************/
extern XtPointer _XmStringUngenerate(XmString, XmStringTag,
XmTextType, XmTextType);
extern void SubpanelControlCreate (SubpanelData *, ControlData *, ControlData *,
Widget, Boolean, Boolean);
extern void WmSubpanelPosted (Display *, Window);
extern int PushRecallGetData (char *);
extern void SwitchButtonCreate (SwitchData *, Boolean);
extern void AddControlActionList (ControlData *);
void ArrowCB (Widget, XtPointer, XtPointer);
void HandleInputCB (Widget, XtPointer, XtPointer);
void MinimizeInputCB (Widget, XtPointer, XtPointer);
void MenuInputCB (Widget, XtPointer, XtPointer);
void SwitchButtonCB (Widget, XtPointer, XtPointer);
void PushCB (Widget, XtPointer, XtPointer);
void SubpanelUnmapCB (Widget, XtPointer, XtPointer);
void SubpanelTornEventHandler (Widget, XtPointer, XEvent *, Boolean *);
Boolean CheckControlTypeFile (ControlData *);
static void SwitchRenameCancel (Widget, XEvent *, String *, Cardinal *);
static void SwitchRenameCB (Widget, XtPointer, XtPointer);
static void GetValuesFromDataType(char *, char *, SubpanelData *,
ElementValue **);
void SwitchRenameLabel (Widget, BoxData *);
void DropCB (Widget, XtPointer, XtPointer);
void TransferDropCB (Widget, XtPointer, XtPointer);
void CustomizeDropCB (Widget, XtPointer, XtPointer);
void CustomizeTransferDropCB (Widget, XtPointer, XtPointer);
/* Translations and action definitions */
/* These are used specifically for the text field overlay */
/* on the switch button for renaming the workspace. They */
/* are necessary for handling escape key processing. */
static char translations_escape[] = "<Key>osfCancel:Escape()";
static XtActionsRec action_table[] = {
{"Escape", SwitchRenameCancel},
};
/************************************************************************
*
* File local globals.
*
************************************************************************/
extern String post_arrow_image;
extern String unpost_arrow_image;
extern String post_monitor_arrow_image;
extern String unpost_monitor_arrow_image;
extern String blank_arrow_image;
extern String dropzone_image;
extern String indicator_on_image;
extern String indicator_off_image;
/************************************************************************
*
* CallWmFunction
* Call the specified WmFunction function with appropriate args
*
************************************************************************/
void
CallWmFunction (WmFunction wm_function,
String args,
Widget client,
XEvent * event)
{
WmGlobalData * wm_global_data = (WmGlobalData *) panel.global_data;
ClientData * wm_client_data = NULL;
Display * display = wm_global_data->display;
Window client_window = XtWindow(client);
/*
* Find the window manager client data for this client
*/
XFindContext (display, client_window, wm_global_data->windowContextType,
(XtPointer) &wm_client_data);
if (wm_client_data == NULL)
return;
/*
* Execute the window manager function
*/
wm_function (args, wm_client_data, event);
}
/************************************************************************
*
* ArrowCB
* Process the callback on the subpanel posting/unposting arrow
*
************************************************************************/
void
ArrowCB (Widget w,
XtPointer client_data,
XtPointer call_data)
{
ControlData * control_data = (ControlData *) client_data;
SubpanelData * subpanel_data = control_data->subpanel_data;
Arg al[2];
int ac;
/* If the subpanel's shell is not managed, this is a request to post */
/* the subpanel. Otherwise it is an unpost request. */
/* Reset the arrow image after the post or unpost. */
if (!XtIsManaged (subpanel_data->shell))
{
Position x = XtX (control_data->arrow);
Position y = XtY (control_data->arrow);
XtSetMappedWhenManaged (subpanel_data->shell, False);
XtManageChild (subpanel_data->form);
XtTranslateCoords (w, 0, 0, &x, &y);
x--;
XtSetArg (al[0], XmNx, x);
XtSetValues (subpanel_data->form, al, 1);
XtManageChild (subpanel_data->shell);
XtSetMappedWhenManaged (subpanel_data->shell, True);
ac = 0;
XtSetArg (al[ac], XmNimageName, unpost_arrow_image); ac++;
XtSetValues (w, al, ac);
}
else
{
/* Execute the window manager function to unpost the subpanel */
CallWmFunction (F_Kill, NULL, subpanel_data->shell, NULL);
}
}
/************************************************************************
*
* HandleInputTranslations
* Return translation table suitable for HandleInputCB
*
************************************************************************/
XtTranslations
HandleInputTranslations(void)
{
static XtTranslations handle_translations;
if (handle_translations == NULL)
{
handle_translations = XtParseTranslationTable(
"<BtnDown>: DrawingAreaInput() ManagerGadgetArm()\n\
<BtnUp>: DrawingAreaInput() ManagerGadgetActivate()\n\
<Btn1Motion>: DrawingAreaInput() ManagerGadgetButtonMotion()\n\
<Btn2Motion>: DrawingAreaInput() ManagerGadgetButtonMotion()");
}
return handle_translations;
}
/************************************************************************
*
* HandleInputCB
* Process button events on the frontpanel handles.
*
************************************************************************/
void
HandleInputCB (Widget w,
XtPointer client_data,
XtPointer call_data)
{
XmAnyCallbackStruct * callback;
XEvent * event;
XButtonEvent * buttonEvent;
XMotionEvent * motionEvent;
callback = (XmAnyCallbackStruct *) call_data;
event = (XEvent *) callback->event;
buttonEvent = (XButtonEvent *) event;
motionEvent = (XMotionEvent *) event;
if (event->type == ButtonPress)
{
if (buttonEvent->button == wmGD.bMenuButton)
{
XUngrabPointer (XtDisplay (w), buttonEvent->time);
XSync (XtDisplay (w), FALSE);
CallWmFunction (F_Post_FpMenu, NULL, panel.shell, event);
}
else
{
wmGD.preMove = True;
wmGD.preMoveX = buttonEvent->x_root;
wmGD.preMoveY = buttonEvent->y_root;
if (buttonEvent->button == Button1)
{
CallWmFunction (F_Raise, NULL, panel.shell, event);
XSync (DISPLAY, FALSE);
XmUpdateDisplay (panel.shell);
}
}
}
else if (event->type == ButtonRelease)
{
wmGD.preMove = False;
}
else if (event->type == MotionNotify && wmGD.preMove)
{
int diffX, diffY;
diffX = motionEvent->x_root - wmGD.preMoveX;
if (diffX < 0) diffX = -diffX;
diffY = motionEvent->y_root - wmGD.preMoveY;
if (diffY < 0) diffY = -diffY;
if (diffX >= wmGD.moveThreshold || diffY >= wmGD.moveThreshold)
{
XUngrabPointer (XtDisplay (w), motionEvent->time);
XSync (XtDisplay (w), FALSE);
CallWmFunction (F_Move, NULL, panel.shell, event);
wmGD.preMove = False;
}
}
}
/************************************************************************
*
* MinimizeInputCB
* Process button events on the frontpanel minimize button.
*
************************************************************************/
void
MinimizeInputCB (Widget w,
XtPointer client_data,
XtPointer call_data)
{
XmAnyCallbackStruct * callback;
XEvent * event;
XButtonEvent * bevent;
extern Pixmap minimize_normal_pixmap;
extern Pixmap minimize_selected_pixmap;
Arg al[1];
callback = (XmAnyCallbackStruct *) call_data;
event = (XEvent *) callback->event;
bevent = (XButtonEvent *) event;
/* On the BSelect button press, change the image to the selected
* minimize image. On the release, check to see if the release
* occurred within the minimize button before minimizing.
* On BMenu button press, post the front panel menu.
*/
if (event->type == ButtonPress)
{
if (bevent->button == Button1)
{
XtSetArg (al[0], XmNbackgroundPixmap, minimize_selected_pixmap);
XtSetValues (w, al, 1);
}
else if (bevent->button == wmGD.bMenuButton)
{
XUngrabPointer (XtDisplay (w), bevent->time);
XSync (XtDisplay (w), FALSE);
CallWmFunction (F_Post_FpMenu, NULL, panel.shell, event);
}
}
else if (event->type == ButtonRelease && bevent->button == Button1)
{
if (bevent->x >= 0 && bevent->x <= (Position) XtWidth(w) &&
bevent->y >= 0 && bevent->y <= (Position) XtHeight(w))
{
CallWmFunction (F_Minimize, NULL, panel.shell, event);
}
XtSetArg (al[0], XmNbackgroundPixmap, minimize_normal_pixmap);
XtSetValues (w, al, 1);
}
}
/************************************************************************
*
* MenuInputCB
* Process button events on the front panel menu button.
*
************************************************************************/
void
MenuInputCB (Widget w,
XtPointer client_data,
XtPointer call_data)
{
XmAnyCallbackStruct * callback;
XEvent * event;
XButtonEvent * bevent;
callback = (XmAnyCallbackStruct *) call_data;
event = (XEvent *) callback->event;
bevent = (XButtonEvent *) event;
/*
* On BSelect or BMenu button press post the front panel system menu
*/
if (event->type == ButtonPress &&
(bevent->button == Button1 || bevent->button == wmGD.bMenuButton))
{
XUngrabPointer (XtDisplay (w), bevent->time);
XSync (XtDisplay (w), FALSE);
CallWmFunction (F_Post_FpMenu, NULL, panel.shell, event);
}
}
/************************************************************************
************************************************************************
The next block of functions are used for the switch button switching,
renaming functionality, and add and delete of workspaces.
************************************************************************
************************************************************************/
/************************************************************************
*
* WorkspaceAdjustPanelPosition
* After a workspace button has been added or deleted, if the panel
* has changed sizes, reposition the panel to keep the same relative
* positioning.
*
* Inputs: x - the original x coordinate of the panel
* y - the original y coordinate of the panel
* width - the original width of the panel
* height - the original height of the panel
*
************************************************************************/
void
WorkspaceAdjustPanelPosition (Position x,
Position y,
Dimension width,
Dimension height)
{
Dimension screen_width;
Dimension screen_height;
int panel_center;
Dimension new_width;
Dimension new_height;
Position new_x;
Position new_y;
Arg al[2];
int ac;
screen_width = WidthOfScreen (XtScreen (panel.shell));
screen_height = HeightOfScreen (XtScreen (panel.shell));
/* Reposition the panel to keep it centered relative to where */
/* it was positioned before the deletion of the button. */
ac = 0;
new_width = XtWidth (panel.shell);
if (new_width != width || x + (Position) new_width > (Position) screen_width)
{
panel_center = x + width / 2 - 1;
new_x = panel_center - new_width / 2 - 4;
if (new_x < 0)
new_x = 0;
else if (new_x + (Position) new_width > (Position) screen_width)
new_x = screen_width - new_width - 4;
XtSetArg (al[ac], XmNx, new_x); ac++;
}
/* Keep the panel to the bottom of the screen, if it was there. */
/* But make sure that it does not go below the bottom. */
new_height = XtHeight (panel.shell);
if (new_height != height || (Dimension)(new_height + y - 1) > screen_height)
{
if (new_height < height && y > (Position)(screen_height / 2))
{
new_y = y + (Position)(height - new_height - 4);
XtSetArg (al[ac], XmNy, new_y); ac++;
}
else if ((Dimension)(new_height + y - 1) > screen_height)
{
new_y = (Position)(screen_height - new_height - 4);
XtSetArg (al[ac], XmNy, new_y); ac++;
}
}
if (ac != 0)
XtSetValues (panel.shell, al, ac);
}
/************************************************************************
*
* WorkspaceModifyCB
* Called by the workspace manager API to send notification of
* configuration changes to the workspace. The types of changes
* processed by this function are workspace add, delete, and rename.
*
************************************************************************/
void
WorkspaceModifyCB (Widget w,
Atom atom_name,
int type,
XtPointer client_data)
{
SwitchData * switch_data = (SwitchData *) client_data;
BoxData * box_data = switch_data->box_data;
DtWsmWorkspaceInfo * workspace_info;
Position x;
Position y;
Dimension width;
Dimension height;
Dimension screen_width;
x = XtX (panel.shell);
y = XtY (panel.shell);
width = XtWidth (panel.shell);
height = XtHeight (panel.shell);
screen_width = WidthOfScreen (XtScreen (panel.shell));
DtWsmGetWorkspaceInfo (XtDisplay (w), RootWindowOfScreen (XtScreen (w)),
atom_name, &workspace_info);
switch (type)
{
/* Increase the size of the switch names and button and call */
/* the function to create the new workspace switch button */
case DtWSM_REASON_ADD:
{
int switch_count;
Atom * atom_names;
/* Cancel workspace renaming */
if (XtIsManaged (box_data->switch_edit))
SwitchRenameCancel (box_data->switch_edit, NULL, NULL, NULL);
DtWsmGetWorkspaceList (XtDisplay (switch_data->rc),
RootWindowOfScreen (XtScreen (switch_data->rc)),
&atom_names, &switch_count);
XFree (switch_data->atom_names);
switch_data->atom_names = atom_names;
switch_data->switch_count = switch_count;
switch_data->switch_names =
(char **) XtRealloc ((char *) switch_data->switch_names,
sizeof (char *) * switch_data->switch_count);
switch_data->switch_names[switch_data->switch_count - 1] =
XtNewString (workspace_info->pchTitle);
switch_data->buttons =
(Widget *) XtRealloc ((char *) switch_data->buttons,
sizeof (Widget) * switch_data->switch_count);
SwitchButtonCreate (switch_data, True);
/* When adding a switch buttons, keep the row columns row count */
/* equal to the requested value with small number of buttons */
if (switch_data->switch_count <= (intptr_t)
(switch_data->element_values[SWITCH_NUMBER_OF_ROWS].parsed_value))
{
Arg al[1];
panel.switch_row_count = (intptr_t)
(switch_data->element_values[SWITCH_NUMBER_OF_ROWS].parsed_value);
XtSetArg (al[0], XmNnumColumns, panel.switch_row_count);
XtSetValues (switch_data->rc, al, 1);
}
/* If the fp width is greater than the screen, increase the */
/* row count */
if (XtWidth (panel.shell) > screen_width)
{
Arg al[1];
panel.switch_row_count++;
XtSetArg (al[0], XmNnumColumns, panel.switch_row_count);
XtSetValues (switch_data->rc, al, 1);
}
WorkspaceAdjustPanelPosition (x, y, width, height);
}
break;
/* Loop through the current set of atom names, comparing */
/* them with the atom of the workspace to be deleted. When */
/* free up the associated data and readjust the name, button */
/* and atom lists. */
case DtWSM_REASON_DELETE:
{
int i;
int j;
int switch_count;
Atom * atom_names;
Arg al[1];
Dimension button_spacing;
Dimension button_width;
/* Cancel workspace renaming */
if (XtIsManaged (box_data->switch_edit))
SwitchRenameCancel (box_data->switch_edit, NULL, NULL, NULL);
DtWsmGetWorkspaceList (XtDisplay (switch_data->rc),
RootWindowOfScreen (XtScreen (switch_data->rc)),
&atom_names, &switch_count);
for (i = 0; i < switch_data->switch_count; i++)
{
if (atom_name == switch_data->atom_names[i])
{
if (switch_data->active_switch > i)
switch_data->active_switch--;
XtFree (switch_data->switch_names[i]);
XtDestroyWidget (switch_data->buttons[i]);
XFree (switch_data->atom_names);
switch_data->atom_names = atom_names;
switch_data->switch_count = switch_count;
for (j = i; j < switch_data->switch_count; j++)
{
switch_data->switch_names[j] = switch_data->switch_names[j+1];
switch_data->buttons[j] = switch_data->buttons[j + 1];
}
break;
}
}
/* When deleting a switch button, keep trying to decrease the */
/* row count to the requested value. */
if (panel.switch_row_count > (intptr_t)
(switch_data->element_values[SWITCH_NUMBER_OF_ROWS].parsed_value))
{
button_width = XtWidth (switch_data->buttons[0]);
XtSetArg (al[0], XmNspacing, &button_spacing);
XtGetValues (switch_data->rc, al, 1);
if ((int)(screen_width - (width + button_width + button_spacing)) >
0)
{
panel.switch_row_count--;
XtSetArg (al[0], XmNnumColumns, panel.switch_row_count);
XtSetValues (switch_data->rc, al, 1);
}
}
WorkspaceAdjustPanelPosition (x, y, width, height);
}
break;
/* Loop through the current set of atom names, comparing */
/* them with the new atom. When a match is found, reset the */
/* the switch name to the new one and update the button label. */
case DtWSM_REASON_TITLE:
{
XmString toggle_string;
Arg al[2];
int i;
for (i = 0; i < switch_data->switch_count; i++)
{
if (atom_name == switch_data->atom_names[i])
{
switch_data->switch_names[i] =
XtNewString (workspace_info->pchTitle);
toggle_string =
XmStringCreateLocalized (workspace_info->pchTitle);
XtSetArg (al[0], XmNstring, toggle_string);
XtSetValues (switch_data->buttons[i], al, 1);
XmStringFree (toggle_string);
XtSetArg (al[0], XmNiconName, workspace_info->pchTitle);
XtSetArg (al[1], XmNtitle, workspace_info->pchTitle);
XtSetValues (panel.shell, al, 2);
break;
}
}
}
break;
/* Loop through the set of switch atom names to find the one */
/* that is now active. Unset the old workspace button and */
/* set the new one referenced by the atom. */
case DtWSM_REASON_CURRENT:
{
int i;
Arg al[2];
for (i = 0; i < switch_data->switch_count; i++)
{
if (switch_data->atom_names[i] == atom_name)
{
XtSetArg (al[0], XmNiconName, switch_data->switch_names[i]);
XtSetArg (al[1], XmNtitle, switch_data->switch_names[i]);
XtSetValues (panel.shell, al, 2);
_DtIconSetState (switch_data->buttons[switch_data->active_switch], False, False);
switch_data->active_switch = i;
_DtIconSetState (switch_data->buttons[switch_data->active_switch], True, False);
break;
}
}
}
break;
}
DtWsmFreeWorkspaceInfo (workspace_info);
}
/************************************************************************
*
* SwitchButtonCB
* Process callbacks on the switch buttons. This function cause
* either the workspace switch to occur or for the switch button
* label to become editable.
*
************************************************************************/
void
SwitchButtonCB (Widget w,
XtPointer client_data,
XtPointer call_data)
{
DtControlCallbackStruct * callback = (DtControlCallbackStruct *) call_data;
XEvent * event = callback->event;
Widget switch_button = w;
Widget old_switch_button;
BoxData * box_data;
SwitchData * switch_data;
Atom atom_name;
int i;
int ac;
Arg al[2];
if (callback->reason != XmCR_VALUE_CHANGED) return;
ac = 0;
XtSetArg (al[ac], XmNuserData, &box_data); ac++;
XtGetValues (switch_button, al, ac);
switch_data = box_data->switch_data;
old_switch_button = switch_data->buttons[switch_data->active_switch];
/* If the selection occurred on a non-selected button, find the atom */
/* representing the workspace name of the button that was selected */
/* and use it to call the workspace manager API to switch the */
/* workspace. The indication on the buttons occurs out of the */
/* called from the workspace manager API. */
/* */
/* If the selection occurred on the current button, set up the name */
/* change editing functions. */
if (switch_button != old_switch_button)
{
/* See if the workspace name is being edited. If so, call the */
/* callback function to accept the changes. */
if (XtIsManaged (box_data->switch_edit))
{
Widget edit_switch_button;
XtSetArg (al[0], XmNuserData, &edit_switch_button);
XtGetValues (box_data->switch_edit, al, 1);
SwitchRenameCB (box_data->switch_edit,
(XtPointer) edit_switch_button, (XtPointer) NULL);
XmProcessTraversal (w, XmTRAVERSE_CURRENT);
}
if (event->xany.type == ButtonRelease)
switch_data->time_stamp = event->xbutton.time;
for (i = 0; i < switch_data->switch_count; i++)
{
if (switch_button == switch_data->buttons[i])
{
XtSetArg (al[0], XmNiconName, switch_data->switch_names[i]);
XtSetArg (al[1], XmNtitle, switch_data->switch_names[i]);
XtSetValues (panel.shell, al, 2);
DtWsmSetCurrentWorkspace (XtParent (switch_button),
switch_data->atom_names[i]);
break;
}
}
_DtIconSetState (old_switch_button, False, False);
}
else
{
/* Don't do anything on double click */
if (event->xany.type == ButtonRelease)
{
if ((event->xbutton.time - switch_data->time_stamp) >
XtGetMultiClickTime(XtDisplay(panel.shell)))
{
switch_data->time_stamp = event->xbutton.time;
SwitchRenameLabel (w, box_data);
}
}
_DtIconSetState (w, True, False);
}
}
/************************************************************************
*
* SwitchRenameCancel
* This is the XtActionProc that gets called when a user types
* escape in a text widget which has this translation tied to it.
*
***********************************************************************/
static void
SwitchRenameCancel (Widget w,
XEvent * event,
String * params,
Cardinal * num_params)
{
Widget switch_button;
Arg al[1];
/* Extract the toggle button from the text field's user data */
XtSetArg (al[0], XmNuserData, &switch_button);
XtGetValues (w, al, 1);
/* Remove the callbacks to eliminate double processing */
XtRemoveAllCallbacks (w, XmNactivateCallback);
/* Unmanage the text widget, set the traversal to the button and exit */
XtUnmanageChild (w);
XmProcessTraversal (switch_button, XmTRAVERSE_CURRENT);
}
/************************************************************************
*
* SwitchRenameCB
* Process callbacks on the text field when a switch name is
* being edited.
*
************************************************************************/
static void
SwitchRenameCB (Widget w,
XtPointer client_data,
XtPointer call_data)
{
Widget switch_button = (Widget) client_data;
char * edit_string;
BoxData * box_data;
SwitchData * switch_data;
Boolean valid;
int current_switch = 0;
int i;
int ac;
Arg al[2];
/* Remove the callbacks to eliminate double processing */
XtRemoveCallback (w, XmNactivateCallback,
SwitchRenameCB, (XtPointer) client_data);
/* If this callback has been called and the text widget is already */
/* unmanaged, it means that the escape key was pressed, so return */
if (XtIsManaged(w) == False) return;
/* Process the two reasons this callback is invoked. A <Return> */
/* key has been pressed or the focus is being moved. Accept the */
/* new name for both conditions. */
ac = 0;
XtSetArg (al[ac], XmNuserData, &box_data); ac++;
XtGetValues (switch_button, al, ac);
switch_data = box_data->switch_data;
for (i = 0; i < switch_data->switch_count; i++)
if (switch_data->buttons[i] == switch_button)
current_switch = i;
/* Get the new name from the text field */
edit_string = (char *) XmTextFieldGetString (w);
/* Verify that title is valid and unique and if so, validate */
/* uniqueness and then change the toggle and workspace internal */
/* information. */
valid = True;
_DtStripSpaces (edit_string);
if (strlen (edit_string) == 0)
valid = False;
else
{
for (i = 0; i < switch_data->switch_count; i++)
{
if (strcmp (switch_data->switch_names[i], edit_string) == 0)
{
if (i == current_switch)
{
XtUnmanageChild (w);
XmProcessTraversal (switch_button, XmTRAVERSE_CURRENT);
XtFree (edit_string);
return;
}
else
{
valid = False;
break;
}
}
}
}
/* If the title is not valid, post and error dialog and */
/* then leave the text field active to allow reediting. */
/* Otherwise, change the title. */
if (!valid)
{
char * s1;
char * s2;
s1 = FPGETMESSAGE (86, 1, "Workspace Manager - Rename Error");
s1 = XtNewString (s1);
s2 = FPGETMESSAGE (86, 2, "Invalid or duplicate workspace name"),
s2 = XtNewString (s2);
_DtMessage (XtParent (w), s1, s2, NULL, NULL);
XtFree (s1);
XtFree (s2);
}
else
_DtWsmSetWorkspaceTitle (panel.shell,
switch_data->atom_names[current_switch],
edit_string);
/* Unmanage the text field and exit */
XtFree (edit_string);
XtUnmanageChild (w);
}
/************************************************************************
*
* SwitchRenameLabel
* Set up the text field and callbacks needed for renaming a
* workspace.
*
************************************************************************/
void
SwitchRenameLabel (Widget switch_button,
BoxData * box_data)
{
Widget switch_edit = box_data->switch_edit;
static Boolean first = True;
XmString toggle_string;
Position toggle_x;
Position toggle_y;
Dimension toggle_width;
Dimension toggle_height;
XmFontList toggle_font_list;
Pixel toggle_background;
Position switch_rc_x;
Position switch_rc_y;
char * edit_string;
XtTranslations trans_table;
int ac;
Arg al[15];
/* Add the additional actions needed by the panel and */
/* set up translations in main edit widget */
if (first)
{
first = False;
XtAppAddActions(XtWidgetToApplicationContext(panel.shell),action_table,1);
trans_table = XtParseTranslationTable (translations_escape);
XtOverrideTranslations (switch_edit, trans_table);
}
/* Extract the label and toggle position */
ac = 0;
XtSetArg (al[ac], XmNx, &toggle_x); ac++;
XtSetArg (al[ac], XmNy, &toggle_y); ac++;
XtSetArg (al[ac], XmNwidth, &toggle_width); ac++;
XtSetArg (al[ac], XmNheight, &toggle_height); ac++;
XtSetArg (al[ac], XmNstring, &toggle_string); ac++;
XtSetArg (al[ac], XmNfontList, &toggle_font_list); ac++;
XtGetValues (switch_button, al, ac);
/* Extract the switch_rc's position */
switch_rc_x = XtX (XtParent (switch_button));
switch_rc_y = XtY (XtParent (switch_button));
/* Convert the xm string into a char string for editing and */
/* then create the text widget to perform the name editing. */
if ((edit_string =
(char *)_XmStringUngenerate(toggle_string, NULL,
XmCHARSET_TEXT, XmCHARSET_TEXT))
!= (char *)NULL)
{
/* Set the switch editing field to the new resource set */
ac = 0;
XtSetArg (al[ac], XmNleftOffset, toggle_x + switch_rc_x); ac++;
XtSetArg (al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
XtSetArg (al[ac], XmNtopOffset, toggle_y + switch_rc_y); ac++;
XtSetArg (al[ac], XmNtopAttachment, XmATTACH_FORM); ac++;
XtSetArg (al[ac], XmNmarginWidth, 4); ac++;
XtSetArg (al[ac], XmNmarginHeight, 0); ac++;
XtSetArg (al[ac], XmNfontList, toggle_font_list); ac++;
XtSetArg (al[ac], XmNhighlightThickness, 1); ac++;
XtSetArg (al[ac], XmNvalue, edit_string); ac++;
XtSetArg (al[ac], XmNuserData, switch_button); ac++;
XtSetValues (switch_edit, al, ac);
XtFree(edit_string);
ac = 0;
XtSetArg (al[ac], XmNcursorPosition,
XmTextFieldGetLastPosition (switch_edit)); ac++;
XtSetArg (al[ac], XmNwidth, toggle_width); ac++;
XtSetArg (al[ac], XmNheight, toggle_height); ac++;
XtSetValues (switch_edit, al, ac);
/* Add the callbacks for the text input processing */
XtAddCallback (switch_edit, XmNactivateCallback,
SwitchRenameCB, (XtPointer) switch_button);
XtManageChild (switch_edit);
XRaiseWindow (XtDisplay (switch_edit), XtWindow (switch_edit));
XSetInputFocus (XtDisplay (switch_edit), XtWindow (panel.shell),
RevertToParent, CurrentTime);
XmProcessTraversal (switch_edit, XmTRAVERSE_CURRENT);
}
XmStringFree (toggle_string);
}
/************************************************************************
************************************************************************
The next block of functions are used for the push and drop callbacks
on all of the panel controls.
************************************************************************
************************************************************************/
/************************************************************************
*
* CheckControlTypeFile
* Check the control if it is of type "file" that the file exists
* before performing a push or drop action.
*
* Inputs: control_data - the control whose file type and status are
* to be checked.
*
************************************************************************/
Boolean
CheckControlTypeFile (ControlData * control_data)
{
struct stat stat_info;
char * file_name;
char * title;
char * msg;
char * message;
if ((intptr_t) control_data->element_values[CONTROL_TYPE].parsed_value != CONTROL_FILE)
return (True);
file_name =
(char *) control_data->element_values[CONTROL_FILE_NAME].parsed_value;
if (lstat (file_name, &stat_info) == 0)
return (True);
/* Display an error dialog because the file cannot be found */
title = FPGETMESSAGE (86, 9, "Workspace Manager - Icon Action Error");
title = XtNewString (title);
msg = FPGETMESSAGE (86, 7, "Cannot find the file");
message = XtMalloc (strlen (msg) + strlen (file_name) + 2);
sprintf (message, "%s %s", msg, file_name);
_DtMessage (panel.shell, title, message, NULL, NULL);
XtFree (title);
XtFree (message);
return (False);
}
/************************************************************************
*
* FreeFunctionArg
* Free the function argument
*
************************************************************************/
static void
FreeFunctionArg (
WmFunction wmFunc,
void *pArg)
{
if (pArg != NULL)
{
if (wmFunc == F_Action)
{
WmActionArg *pAP = (WmActionArg *) pArg;
if (pAP->aap != NULL)
{
int i;
for (i=0; i < pAP->numArgs; i++)
{
if (pAP->aap[i].u.file.name != NULL)
XtFree ((char *) pAP->aap[i].u.file.name);
}
XtFree ((char *) pAP->aap);
}
if (pAP->actionName != NULL)
XtFree ((char *) pAP->actionName);
if (pAP->szExecParms != NULL)
XtFree ((char *) pAP->szExecParms);
}
XtFree ((char *) pArg);
}
}
Boolean
CheckOtherMonitorsOn(SubpanelData * subpanel_data)
{
int i;
ControlData * control_data;
Boolean m_state;
for (i = -1; i < subpanel_data->control_data_count; i++)
{
if (i == -1)
{
m_state = _DtControlGetMonitorState(subpanel_data->main_panel_icon_copy);
}
else
{
control_data = subpanel_data->control_data[i];
m_state = _DtControlGetMonitorState(control_data->icon);
}
if (m_state == DtMONITOR_ON) return True;
}
return False;
}
/************************************************************************
*
* PushCB
* Process the callback on a control.
*
************************************************************************/
void
PushCB (Widget w,
XtPointer client_data,
XtPointer call_data)
{
int control_behavior;
DtControlCallbackStruct * callback = (DtControlCallbackStruct *) call_data;
XEvent * event = callback->event;
ControlData * control_data = (ControlData *) client_data;
int control_type;
PanelActionData * push_action;
Boolean push_recall;
Boolean unpost_subpanel = True;
BoxData * box_data;
SubpanelData * subpanel_data;
ControlData * main_control_data = NULL;
char m_state;
Widget * pWid;
Widget monitor_icon;
Arg al[1];
int i, j;
control_behavior = (intptr_t) (panel.element_values[PANEL_CONTROL_BEHAVIOR].parsed_value);
/* See if the workspace name is being edited. If so, call the */
/* callback function to accept the changes. */
for (i = 0; i < panel.box_data_count; i++)
{
if (panel.box_data[i]->switch_edit != NULL)
{
if (XtIsManaged (panel.box_data[i]->switch_edit))
{
Widget switch_button;
XtSetArg (al[0], XmNuserData, &switch_button);
XtGetValues (panel.box_data[i]->switch_edit, al, 1);
SwitchRenameCB (panel.box_data[i]->switch_edit,
(XtPointer) switch_button, (XtPointer) NULL);
XmProcessTraversal (w, XmTRAVERSE_CURRENT);
break;
}
}
}
/* See if the control action occurred out of a subpanel. If so, */
/* get the subpanel and set the main control data. */
if (control_data->parent_type == SUBPANEL)
{
subpanel_data = (SubpanelData *) control_data->parent_data;
main_control_data = subpanel_data->parent_control_data;
/* This control may have been toggled from the subpanel. If */
/* so, make sure the subpanel is not reposted. */
if (XtParent (w) != subpanel_data->form)
unpost_subpanel = False;
}
else
{
/* The control may be the main panel icon copy. If so, find */
/* the subpanel that contains it a set the subpanel data */
subpanel_data = NULL;
for (i = 0; i < panel.box_data_count; i++)
{
for (j = 0; j < panel.box_data[i]->control_data_count; j++)
{
ControlData * box_control;
box_control = panel.box_data[i]->control_data[j];
if (box_control->subpanel_data != NULL &&
box_control->subpanel_data->main_panel_icon_copy == w)
{
subpanel_data = box_control->subpanel_data;
main_control_data = subpanel_data->parent_control_data;
break;
}
}
if (subpanel_data != NULL)
break;
}
}
/* If the input occurred out of a subpanel, check to see if */
/* the input was an escape key. If so, unpost the subpanel */
/* and return. */
if (subpanel_data != NULL && event != NULL)
{
if (event->xany.type == KeyPress)
{
int count;
char buffer[10];
int bufsize = 10;
KeySym keysym;
XComposeStatus compose;
static Boolean first = True;
count = XLookupString ((XKeyEvent *)event, buffer, bufsize,
&keysym, &compose);
if (keysym == XK_Escape)
{
if (first)
{
ArrowCB (main_control_data->arrow,
(XtPointer)main_control_data, (XtPointer)NULL);
first = False;
}
else
first = True;
return;
}
}
}
/* This function handles four callback reasons. Two of them, */
/* START and STOP show and remove an hour glass cursor. */
/* MONITOR modifies subpanel visuals when a file change is */
/* detected. ACTIVATE/DEFAULT_ACTION handle the activation */
/* of a control. */
if (callback->reason == XmCR_BUSY_START)
{
XDefineCursor (XtDisplay (panel.shell), XtWindow (panel.shell),
panel.busy_cursor);
for (i = 0, pWid = M_PopupList (panel.shell);
i < M_NumPopups (panel.shell); i++)
XDefineCursor (XtDisplay (panel.shell), XtWindow (pWid[i]),
panel.busy_cursor);
}
else if (callback->reason == XmCR_BUSY_STOP)
{
XUndefineCursor (XtDisplay (panel.shell), XtWindow (panel.shell));
for (i = 0, pWid = M_PopupList (panel.shell);
i < M_NumPopups (panel.shell); i++)
XUndefineCursor (XtDisplay (panel.shell), XtWindow (pWid[i]));
}
else if (callback->reason == XmCR_MONITOR)
{
/* For a monitor file, turn on the monitor indicator for */
/* the subpanel control and turn on the arrow to the */
/* highlighted arrow of the subpanel. */
if (subpanel_data != NULL)
{
monitor_icon = control_data->indicator;
m_state = _DtControlGetMonitorState(w);
if (m_state == DtMONITOR_ON)
XtSetArg (al[0], XmNimageName, indicator_on_image);
else /* DtMONITOR_OFF */
XtSetArg (al[0], XmNimageName, indicator_off_image);
XtSetValues (monitor_icon, al, 1);
if (XtIsManaged (subpanel_data->shell))
{
if (m_state == DtMONITOR_ON)
{
XtSetArg (al[0], XmNimageName, unpost_monitor_arrow_image);
XtSetValues (main_control_data->arrow, al, 1);
}
else
{
if (!CheckOtherMonitorsOn(subpanel_data))
{
XtSetArg (al[0], XmNimageName, unpost_arrow_image);
XtSetValues (main_control_data->arrow, al, 1);
}
}
}
else
{
if (m_state == DtMONITOR_ON)
{
XtSetArg (al[0], XmNimageName, post_monitor_arrow_image);
XtSetValues (main_control_data->arrow, al, 1);
}
else
{
if (!CheckOtherMonitorsOn(subpanel_data))
{
XtSetArg (al[0], XmNimageName, post_arrow_image);
XtSetValues (main_control_data->arrow, al, 1);
}
}
}
}
}
else if ((control_behavior == DOUBLE_CLICK &&
callback->reason == XmCR_DEFAULT_ACTION) ||
(control_behavior == SINGLE_CLICK &&
(callback->reason == XmCR_DEFAULT_ACTION ||
callback->reason == XmCR_SINGLE_SELECT)))
{
control_type = (intptr_t) (control_data->element_values[CONTROL_TYPE].parsed_value);
push_action = (PanelActionData *) (control_data->element_values[CONTROL_PUSH_ACTION].parsed_value);
push_recall = (Boolean) (intptr_t) (control_data->element_values[CONTROL_PUSH_RECALL].parsed_value);
switch (control_type)
{
case CONTROL_CLIENT:
case CONTROL_ICON:
case CONTROL_FILE:
case CONTROL_DATE:
{
/* Turn off the subpanel control monitor indicator */
if ((char) (intptr_t) control_data->element_values[CONTROL_MONITOR_TYPE].
parsed_value != MONITOR_NONE)
{
if (subpanel_data != NULL)
{
monitor_icon = control_data->indicator;
XtSetArg (al[0], XmNimageName, indicator_off_image);
XtSetValues (monitor_icon, al, 1);
}
}
if (CheckControlTypeFile (control_data) && push_action != NULL)
{
_DtControlDoPushAnimation (w);
if (push_recall == False)
{
/* If the control is of type file, build and object */
/* list that contains the host and file name to */
/* pass to the invokation. */
if (control_type == CONTROL_FILE && !control_data->is_action)
{
DtActionArg * aap;
aap = (DtActionArg *) XtCalloc(1,sizeof(DtActionArg));
aap->argClass = DtACTION_FILE;
aap->u.file.name = (char *) control_data->
element_values[CONTROL_FILE_NAME].parsed_value;
DtActionInvoke (panel.shell,
push_action->action_name,
aap, 1, NULL, NULL, NULL,
1, NULL, NULL);
XtFree ((char *) aap);
}
else
{
if (strcmp (push_action->action_name, "FPOnItemHelp") == 0)
{
WmDtHelpMode();
unpost_subpanel = False;
}
else
{
DtActionInvoke (panel.shell,
push_action->action_name,
NULL, 0, NULL, NULL, NULL,
1, NULL, NULL);
}
}
}
else
{
WmFunction wm_func;
int function_index;
String func_arg = NULL;
String s1, s1save;
char * client_name;
char * client_title;
WmGlobalData * wm_global_data = (WmGlobalData *) panel.global_data;
ClientData * wm_client_data = NULL;
WmPushRecallArg push_argument;
/* Parse out the function and arguments used by the */
/* window manager to invoke the client. */
s1save = s1 = XtNewString ("f.action");
function_index =
ParseWmFunction ((unsigned char **) &s1, CRS_ANY, &wm_func);
XtFree (s1save);
client_name =
(char *) control_data->element_values[CONTROL_CLIENT_NAME].parsed_value;
if (client_name == NULL)
client_name =
(char *) control_data->element_values[CONTROL_LABEL].parsed_value;
client_title =
(char *) control_data->element_values[CONTROL_LABEL].parsed_value;
if (control_type == CONTROL_FILE && ! control_data->is_action)
{
char * file_name;
file_name = (char *) control_data->
element_values[CONTROL_FILE_NAME].parsed_value;
s1 = XtMalloc (strlen (push_action->action_name) + strlen (file_name) + 2);
strcpy (s1, push_action->action_name);
strcat (s1, " ");
strcat (s1, file_name);
}
else
s1 = XtNewString (push_action->action_name);
ParseWmFunctionArg ((unsigned char **) &s1, function_index,
wm_func, (void **) &func_arg,
client_name, client_name);
/* Set the push argument to the parsed data */
push_argument.ixReg = PushRecallGetData (client_name);
push_argument.wmFunc = wm_func;
push_argument.pArgs = func_arg;
/* Get the window manager client data for the panel and */
/* call the push recall function to get the client run. */
if (subpanel_data != NULL)
XFindContext (wm_global_data->display,
XtWindow (subpanel_data->shell),
wm_global_data->windowContextType,
(XtPointer) &wm_client_data);
else
XFindContext (wm_global_data->display,
XtWindow (panel.shell),
wm_global_data->windowContextType,
(XtPointer) &wm_client_data);
F_Push_Recall ((String) &push_argument,
wm_client_data, callback->event);
FreeFunctionArg (wm_func, func_arg);
XtFree (s1);
}
}
}
break;
case CONTROL_BLANK:
case CONTROL_BUSY:
case CONTROL_CLOCK:
return;
break;
}
/* Call the unposting function and reset the arrow behavior if the */
/* action occurred out of a subpanel. */
if (subpanel_data != NULL && unpost_subpanel &&
(Boolean) (intptr_t) panel.element_values[PANEL_SUBPANEL_UNPOST].parsed_value &&
subpanel_data->torn == False)
ArrowCB (main_control_data->arrow,
(XtPointer)main_control_data, (XtPointer)NULL);
}
}
/************************************************************************
*
* DropCB
* Process the callback for drops on a control
*
************************************************************************/
void
DropCB (Widget w,
XtPointer client_data,
XtPointer call_data)
{
PanelActionData * drop_action = (PanelActionData *) client_data;
DtDndDropAnimateCallback animate_data =
(DtDndDropAnimateCallback) call_data;
ControlData * control_data;
Arg al[1];
int i, j, k, l;
DtActionArg * aap;
char * save_name = NULL;
XtSetArg (al[0], XmNuserData, &control_data);
XtGetValues (w, al, 1);
if (CheckControlTypeFile (control_data) &&
(animate_data->dropData->protocol == DtDND_FILENAME_TRANSFER ||
animate_data->dropData->protocol == DtDND_BUFFER_TRANSFER))
{
int numItems;
intptr_t control_type =
(intptr_t)control_data->element_values[CONTROL_TYPE].parsed_value;
char * control_name =
(char *)control_data->element_values[CONTROL_FILE_NAME].parsed_value;
Boolean send_control_name = False;
_DtControlDoDropAnimation (w);
drop_action = (PanelActionData *)
control_data->element_values[CONTROL_DROP_ACTION].parsed_value;
if (control_data->operation == XmDROP_MOVE)
{
if (control_data->move_action)
{
save_name = drop_action->action_name;
drop_action->action_name = control_data->move_action;
}
}
else if (control_data->operation == XmDROP_COPY)
{
if (control_data->copy_action)
{
save_name = drop_action->action_name;
drop_action->action_name = control_data->copy_action;
}
}
else if (control_data->operation == XmDROP_LINK)
{
if (control_data->link_action)
{
save_name = drop_action->action_name;
drop_action->action_name = control_data->link_action;
}
}
numItems = animate_data->dropData->numItems;
if ((control_type == CONTROL_FILE) &&
(!control_data->is_action) &&
(strcmp(control_name, drop_action->action_name) != 0))
{
++numItems;
send_control_name = True;
}
if (animate_data->dropData->protocol == DtDND_FILENAME_TRANSFER)
{
char ** file_list = animate_data->dropData->data.files;
int m = 0;
aap = (DtActionArg *) XtCalloc (numItems, sizeof (DtActionArg));
if (send_control_name)
{
aap[m].argClass = DtACTION_FILE;
aap[m++].u.file.name =
(char *)control_data->element_values[CONTROL_FILE_NAME].parsed_value;
}
for (l = 0; m < numItems; l++, m++)
{
aap[m].argClass = DtACTION_FILE;
aap[m].u.file.name = file_list[l];
}
}
else if (animate_data->dropData->protocol == DtDND_BUFFER_TRANSFER)
{
DtDndBuffer * buf_list = animate_data->dropData->data.buffers;
int m = 0;
aap = (DtActionArg *) XtCalloc (numItems, sizeof (DtActionArg));
if (send_control_name)
{
aap[m].argClass = DtACTION_FILE;
aap[m++].u.file.name =
(char *)control_data->element_values[CONTROL_FILE_NAME].parsed_value;
}
for (l = 0; m < numItems; l++, m++)
{
aap[m].argClass = DtACTION_BUFFER;
aap[m].u.buffer.bp = buf_list[l].bp;
aap[m].u.buffer.size = buf_list[l].size;
aap[m].u.buffer.name = buf_list[l].name;
}
}
else
{
if (save_name != NULL)
drop_action->action_name = save_name;
control_data->operation = 0;
return;
}
DtActionInvoke (w, drop_action->action_name, aap, numItems,
NULL, NULL, NULL, 1, NULL, NULL);
XtFree((char *) aap);
if (save_name != NULL)
drop_action->action_name = save_name;
control_data->operation = 0;
}
}
/************************************************************************
*
* TransferDropCB
* Process the callback for drops on a control
*
************************************************************************/
void
TransferDropCB (Widget w,
XtPointer client_data,
XtPointer call_data)
{
DtDndTransferCallbackStruct * transfer_data =
(DtDndTransferCallbackStruct *) call_data;
ControlData * control_data;
Arg al[1];
/* Currently only accepts FILE drops */
if (transfer_data->dropData->protocol == DtDND_FILENAME_TRANSFER ||
transfer_data->dropData->protocol == DtDND_BUFFER_TRANSFER)
{
transfer_data->status = DtDND_SUCCESS;
XtSetArg (al[0], XmNuserData, &control_data);
XtGetValues (w, al, 1);
control_data->operation = transfer_data->operation;
}
else
transfer_data->status = DtDND_FAILURE;
transfer_data->completeMove = False;
}
/************************************************************************
************************************************************************
This block of functions handle the processing of subpanel torn-off
behavior. Default behavior for a subpanel is to unpost when a
control is selected. This changes to sticky when the subpanel is torn.
************************************************************************
************************************************************************/
/************************************************************************
*
* SubpanelUnmapCB
* Process the callback on the subpanel unposting initiated through
* the window manager close menu item.
*
************************************************************************/
void
SubpanelUnmapCB (Widget w,
XtPointer client_data,
XtPointer call_data)
{
ControlData * main_control_data = (ControlData *) client_data;
SubpanelData * subpanel_data = main_control_data->subpanel_data;
Arg al[1];
int ac;
ac = 0;
XtSetArg (al[ac], XmNimageName, post_arrow_image); ac++;
XtSetValues (main_control_data->arrow, al, ac);
XtUnmanageChild (subpanel_data->shell);
subpanel_data->torn = False;
/* Remove the event handler from the subpanel */
XtRemoveEventHandler (subpanel_data->shell, StructureNotifyMask, False,
(XtEventHandler) SubpanelTornEventHandler,
(XtPointer) main_control_data);
/* Reset the active traversal control for the front panel */
/* We should not have to do this but for unknown reasons, */
/* the traversal highlight is getting lost. */
XmProcessTraversal (panel.shell, XmTRAVERSE_NEXT);
XmProcessTraversal (panel.shell, XmTRAVERSE_PREV);
}
/************************************************************************
*
* SubpanelTornEventHandler
* Set a subpanel flag to change its posting behavior when it is
* torn off.
*
************************************************************************/
void
SubpanelTornEventHandler (Widget subpanel_shell,
XtPointer client_data,
XEvent * event,
Boolean * continue_dispatch)
{
ControlData * main_control_data = (ControlData *) client_data;
SubpanelData * subpanel_data = main_control_data->subpanel_data;
if (subpanel_data->posted_x != 0 &&
subpanel_data->posted_x != XtX (subpanel_data->shell))
subpanel_data->torn = True;
else
subpanel_data->torn = False;
*continue_dispatch = True;
}
/************************************************************************
*
* StartHelpClient
* Start up the help manager to show the help topic
*
* Inputs: widget - the widget for which help was requested
* help_volume - the help volume that contains the information
* help_topic - the specific help topic.
*
************************************************************************/
void StartHelpClient (Widget widget,
char * help_volume,
char * help_topic)
{
/***** TEMPORARY - Add code to actually invoke the Help Client ****/
WmDtDisplayTopicHelp (widget, help_volume, help_topic);
}
/************************************************************************
*
* InvokeHelp
* Invoke topic help if available otherwise invoke help string if
* available
*
************************************************************************/
void InvokeHelp (Widget widget,
char * help_topic,
char * help_volume,
char * help_string)
{
if (help_volume == NULL)
help_volume = FP_HELP_VOLUME;
if (help_topic != NULL)
{
if (strcmp (help_volume, FP_HELP_VOLUME) == 0)
WmDtDisplayTopicHelp (widget, help_volume, help_topic);
else
StartHelpClient (widget, help_volume, help_topic);
}
else
{
if (help_string != NULL)
WmDtDisplayStringHelp (widget, help_string);
}
}
/************************************************************************
*
* SubpanelTopicHelpCB
* Process the callback for help on the subpanel
*
************************************************************************/
void SubpanelTopicHelpCB (Widget widget,
XtPointer client_data,
XtPointer call_data)
{
SubpanelData * subpanel_data = (SubpanelData *) client_data;
char * help_volume;
char * help_topic;
char * help_string;
help_volume =
(char *) subpanel_data->element_values[SUBPANEL_HELP_VOLUME].parsed_value;
help_topic =
(char *) subpanel_data->element_values[SUBPANEL_HELP_TOPIC].parsed_value;
help_string =
(char *) subpanel_data->element_values[SUBPANEL_HELP_STRING].parsed_value;
InvokeHelp(widget, help_topic, help_volume, help_string);
} /* END OF FUNCTION SubpanelTopicHelpCB */
/************************************************************************
*
* SwitchTopicHelpCB
* Process the callback for help on the switch
*
************************************************************************/
void SwitchTopicHelpCB (Widget widget,
XtPointer client_data,
XtPointer call_data)
{
SwitchData * switch_data = (SwitchData *) client_data;
char * help_volume;
char * help_topic;
char * help_string;
help_volume =
(char *) switch_data->element_values[SWITCH_HELP_VOLUME].parsed_value;
help_topic =
(char *) switch_data->element_values[SWITCH_HELP_TOPIC].parsed_value;
help_string =
(char *) switch_data->element_values[SWITCH_HELP_STRING].parsed_value;
InvokeHelp(widget, help_topic, help_volume, help_string);
} /* END OF FUNCTION SwitchTopicHelpCB */
/************************************************************************
*
* ControlTopicHelpCB
* Process the callback for help on the control
*
*************************************************************************/
void ControlTopicHelpCB (Widget widget,
XtPointer client_data,
XtPointer call_data)
{
ControlData * control_data = (ControlData *) client_data;
char * help_volume;
char * help_topic;
char * help_string;
help_volume =
(char *) control_data->element_values[CONTROL_HELP_VOLUME].parsed_value;
help_topic =
(char *) control_data->element_values[CONTROL_HELP_TOPIC].parsed_value;
help_string =
(char *) control_data->element_values[CONTROL_HELP_STRING].parsed_value;
InvokeHelp(widget, help_topic, help_volume, help_string);
} /* END OF FUNCTION ControlTopicHelpCB */
/************************************************************************
*
* GeneralTopicHelpCB
* Process the callback for help on the control
*
************************************************************************/
void GeneralTopicHelpCB (Widget widget,
XtPointer client_data,
XtPointer call_data)
{
char * help_volume;
char * help_topic;
help_volume = FP_HELP_VOLUME;
help_topic = (char *) client_data;
WmDtDisplayTopicHelp (widget, help_volume, help_topic);
} /* END OF FUNCTION GeneralTopicHelpCB */
/************************************************************************
************************************************************************
This block of functions handle the initialization and dynamic
processing for the subpanel installation area.
************************************************************************
************************************************************************/
/************************************************************************
*
* GetValuesFromDataType
* Given and file type index and subpanel data, construct an element
* values array for a new control that is initialized to the attributes
* of the file type.
*
************************************************************************/
static void
GetValuesFromDataType (char * data_type,
char * file_name,
SubpanelData * subpanel_data,
ElementValue ** element_values)
{
char * ptr;
int i;
*element_values = (ElementValue *) XtMalloc (sizeof(ElementValue) *
CONTROL_KEYWORD_COUNT);
for (i = 0; i < CONTROL_KEYWORD_COUNT; i++)
{
(*element_values)[i].use_default = True;
(*element_values)[i].string_value = NULL;
(*element_values)[i].parsed_value = NULL;
}
(*element_values)[CONTROL_FILE_NAME].string_value = XtNewString (file_name);
ptr = (char *)strrchr(file_name, '/');
ptr++;
(*element_values)[CONTROL_NAME].string_value = XtNewString(ptr);
(*element_values)[CONTROL_TYPE].string_value = XtNewString("file");
(*element_values)[CONTROL_CONTAINER_TYPE].string_value =
XtNewString("SUBPANEL");
(*element_values)[CONTROL_CONTAINER_NAME].string_value =
XtNewString(subpanel_data->element_values[0].string_value);
(*element_values)[CONTROL_POSITION_HINTS].string_value =
XtNewString("last");
InitializeControlFields (*element_values, data_type);
}
/************************************************************************
*
* CustomizeDropCB
* Process the callback for the drop on the subpanel drop zone for
* dynamic customization
*
************************************************************************/
void
CustomizeDropCB (Widget w,
XtPointer client_data,
XtPointer call_data)
{
BoxData * box_data;
ControlData * main_control_data;
SubpanelData * subpanel_data;
DtDndDropAnimateCallbackStruct * animate_data =
(DtDndDropAnimateCallbackStruct *) call_data;
ControlData * control_data;
ElementValue * element_values;
char * data_type;
Boolean drop_of_fp;
Boolean bad_control;
Boolean control_monitor;
intptr_t position_hints;
int count;
char * new_control_name;
char * control_name;
Widget attach_widget;
int i, j, k;
int file_count;
char ** file_list;
Arg al[4];
int ac;
/* If this is not a transfer drop, return */
if (animate_data->dropData->protocol != DtDND_FILENAME_TRANSFER)
return;
/* Get the subpanel, box, and main control data */
XtSetArg (al[0], XmNuserData, &subpanel_data);
XtGetValues (w, al, 1);
main_control_data = subpanel_data->parent_control_data;
box_data = (BoxData *) main_control_data->parent_data;
file_count = animate_data->dropData->numItems;
file_list = animate_data->dropData->data.files;
/* Pop down the subpanel before creating the new control or */
/* mucking with any of the old controls. */
if (subpanel_data->torn == False)
XtUnmanageChild (subpanel_data->shell);
/* Loop through the set of files (possibly more than one) that */
/* have been dropped. */
for (i = 0; i < file_count; i++)
{
/* Get the file type of the file and process as either */
/* a "FrontPanel" file or a normal file type. */
data_type = DtDtsFileToDataType (file_list[i]);
if (!strcmp (data_type, "FP"))
{
drop_of_fp = True;
InitParse (file_list[i], &element_values);
/* Reset the values of the container name and type to this one */
if (element_values[CONTROL_CONTAINER_NAME].use_default == False)
{
if (element_values[CONTROL_CONTAINER_NAME].parsed_value != NULL)
XtFree (element_values[CONTROL_CONTAINER_NAME].parsed_value);
if (element_values[CONTROL_CONTAINER_NAME].string_value != NULL)
XtFree (element_values[CONTROL_CONTAINER_NAME].string_value);
}
if (element_values[CONTROL_CONTAINER_TYPE].use_default == False)
{
if (element_values[CONTROL_CONTAINER_TYPE].string_value != NULL)
XtFree (element_values[CONTROL_CONTAINER_TYPE].string_value);
}
if (element_values[CONTROL_POSITION_HINTS].use_default == False)
{
if (element_values[CONTROL_POSITION_HINTS].string_value != NULL)
XtFree (element_values[CONTROL_POSITION_HINTS].string_value);
}
element_values[CONTROL_CONTAINER_NAME].use_default = False;
element_values[CONTROL_CONTAINER_NAME].string_value =
XtNewString (subpanel_data->element_values[SUBPANEL_NAME].parsed_value);
element_values[CONTROL_CONTAINER_NAME].parsed_value =
XtNewString (subpanel_data->element_values[SUBPANEL_NAME].parsed_value);
element_values[CONTROL_CONTAINER_TYPE].use_default = False;
element_values[CONTROL_CONTAINER_TYPE].string_value =
XtNewString ("SUBPANEL");
element_values[CONTROL_CONTAINER_TYPE].parsed_value =
(char *) SUBPANEL;
element_values[CONTROL_POSITION_HINTS].use_default = False;
element_values[CONTROL_POSITION_HINTS].string_value =
XtNewString ("last");
element_values[CONTROL_POSITION_HINTS].parsed_value =
(char *) 100;
}
else
{
drop_of_fp = False;
GetValuesFromDataType (data_type, file_list[i],
subpanel_data, &element_values);
}
DtDtsFreeDataType (data_type);
/* Check for naming conflicts and if found, issue an error and */
/* clean up. Continue processing subsequent files even if this */
/* one is not valid. */
new_control_name = (char *) element_values[CONTROL_NAME].parsed_value;
bad_control = False;
for (j = 0; j < subpanel_data->control_data_count; j++)
{
control_name = (char *) subpanel_data->control_data[j]->
element_values[CONTROL_NAME].parsed_value;
if (strcmp (control_name, new_control_name) == 0)
{
ControlData control_data;
String title, del_ctrl, ctrl_name, del_msg, message;
/* Display an error dialog for the unusable drop data */
title = FPGETMESSAGE (86, 3, "Workspace Manager - Install Icon Error");
title = XtNewString (title);
del_ctrl = FPGETMESSAGE (86, 4, "Install Icon:");
del_ctrl = XtNewString (del_ctrl);
del_msg = FPGETMESSAGE (86, 8, "There is already an icon of this name.");
del_msg = XtNewString (del_msg);
message = XtMalloc ((strlen(del_ctrl) + strlen(new_control_name) +
strlen(del_msg) + 4));
sprintf(message, "%s %s\n\n%s", del_ctrl, new_control_name, del_msg);
_DtMessage (panel.shell, title, message, NULL, NULL);
XtFree (title);
XtFree (del_ctrl);
XtFree (del_msg);
XtFree (message);
/* Set up a temporary control data structure so that the */
/* appropriate function can be used to free the allocated */
/* element values. */
control_data.element_values = element_values;
RemoveEntry ((RecordData *)&control_data, CONTROL);
bad_control = True;
break;
}
}
if (bad_control) continue;
if ((intptr_t) element_values[CONTROL_MONITOR_TYPE].parsed_value != MONITOR_NONE)
control_monitor = True;
else
control_monitor = False;
position_hints = (intptr_t) element_values[CONTROL_POSITION_HINTS].parsed_value;
/* Initialize the subpanel layout and processing attributes. */
if ((intptr_t) main_control_data->
element_values[CONTROL_MONITOR_TYPE].parsed_value != MONITOR_NONE)
{
control_monitor = True;
}
for (j = 0; j < subpanel_data->control_data_count; j++)
{
if ((intptr_t) subpanel_data->control_data[j]->
element_values[CONTROL_MONITOR_TYPE].parsed_value != MONITOR_NONE)
{
control_monitor = True;
break;
}
}
/* If the new control is a montior, loop through the existing */
/* control set a adjust the left offset resource to ensure */
/* that they are all aligned properly. */
if (control_monitor)
{
XtSetArg (al[0], XmNleftOffset, 20);
for (j = 0; j < subpanel_data->control_data_count; j++)
XtSetValues (subpanel_data->control_data[j]->icon, al, 1);
if (subpanel_data->main_panel_icon_copy != NULL)
XtSetValues (subpanel_data->main_panel_icon_copy, al, 1);
}
/* Get the subpanel control data and position the element */
/* values into the postion hints location. */
/* The remainder of the positioning code is set up to allow */
/* placement in non-last positions even though position is */
/* forced to last. This is here for future use. */
subpanel_data->control_data_count++;
count = subpanel_data->control_data_count;
subpanel_data->control_data =
(ControlData **) XtRealloc ((char *) subpanel_data->control_data,
sizeof (ControlData *) * count);
for (j = count - 2; j >= 0; j--)
{
if (position_hints >=
(intptr_t) subpanel_data->control_data[j]->element_values[CONTROL_POSITION_HINTS].parsed_value)
break;
}
j++;
for (k = count - 1; k > j; k--)
subpanel_data->control_data[k] = subpanel_data->control_data[k - 1];
subpanel_data->control_data[j] = control_data =
(ControlData *) XtMalloc (sizeof (ControlData));
control_data->element_values = element_values;
control_data->parent_data = (XtPointer) subpanel_data;
control_data->parent_type = SUBPANEL;
control_data->subpanel_data = NULL;
control_data->icon = NULL;
control_data->arrow = NULL;
control_data->arrow_separator = NULL;
control_data->indicator = NULL;
control_data->is_action = False;
control_data->move_action = NULL;
control_data->copy_action = NULL;
control_data->link_action = NULL;
control_data->operation = 0;
AddControlActionList (control_data);
if (j == 0 && subpanel_data->main_panel_icon_copy != NULL)
attach_widget = subpanel_data->main_panel_icon_copy;
else
attach_widget = subpanel_data->control_data[j - 1]->icon;
/* Reattach the bottom control so the new bottom will appear */
if (j == count - 1)
{
ac = 0;
XtSetArg (al[ac], XmNbottomAttachment, XmATTACH_NONE); ac++;
XtSetArg (al[ac], XmNbottomOffset, 0); ac++;
XtSetValues (attach_widget, al, ac);
}
SubpanelControlCreate (subpanel_data, main_control_data,
control_data, attach_widget, False,
control_monitor);
/* Pad the bottom control */
if (j == count - 1)
{
ac = 0;
XtSetArg (al[ac], XmNbottomAttachment, XmATTACH_FORM); ac++;
XtSetArg (al[ac], XmNbottomOffset, 5); ac++;
XtSetValues (control_data->icon, al, ac);
}
WriteControlComponentFile (control_data);
}
/* Pop the subpanel back up and return */
if (subpanel_data->torn == False)
ArrowCB (main_control_data->arrow,
(XtPointer)main_control_data, (XtPointer)NULL);
}
/************************************************************************
*
* CustomizeTransferDropCB
* Process the callback for drops on an install zone
*
************************************************************************/
void
CustomizeTransferDropCB (Widget w,
XtPointer client_data,
XtPointer call_data)
{
DtDndTransferCallbackStruct * transfer_data =
(DtDndTransferCallbackStruct *) call_data;
/* Currently only accepts FILE drops */
if (transfer_data->dropData->protocol == DtDND_FILENAME_TRANSFER)
transfer_data->status = DtDND_SUCCESS;
else
transfer_data->status = DtDND_FAILURE;
transfer_data->completeMove = False;
}