1365 lines
34 KiB
C
1365 lines
34 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
|
|
*/
|
|
|
|
/*
|
|
* $XConsortium: ab_utils.c /main/3 1995/11/06 17:13:58 rswiston $
|
|
*
|
|
* @(#)ab_utils.c 1.27 08 May 1995
|
|
*
|
|
* RESTRICTED CONFIDENTIAL INFORMATION:
|
|
*
|
|
* The information in this document is subject to special
|
|
* restrictions in a confidential disclosure agreement between
|
|
* HP, IBM, Sun, USL, SCO and Univel. Do not distribute this
|
|
* document outside HP, IBM, Sun, USL, SCO, or Univel without
|
|
* Sun's specific written approval. This document and all copies
|
|
* and derivative works thereof must be returned or destroyed at
|
|
* Sun's request.
|
|
*
|
|
* Copyright 1993 Sun Microsystems, Inc. All rights reserved.
|
|
*
|
|
*/
|
|
|
|
|
|
/*
|
|
* File: ab_utils.c - file containing ab utilities
|
|
*/
|
|
|
|
|
|
#include <sys/param.h>
|
|
#include <Xm/Xm.h>
|
|
#include <Xm/MessageB.h>
|
|
#include <X11/cursorfont.h>
|
|
#include <ab_private/ab.h>
|
|
#include <ab_private/abobj.h>
|
|
#include <ab_private/abobj_set.h>
|
|
#include <ab_private/ab_utils.h>
|
|
#include <ab_private/pal.h>
|
|
#include <ab_private/proj.h>
|
|
#include <ab_private/trav.h>
|
|
#include <ab_private/obj.h>
|
|
#include <ab_private/objxm.h>
|
|
#include <ab_private/cgen.h>
|
|
#include <ab_private/ui_util.h>
|
|
#include "palette_ui.h"
|
|
#include "dtb_utils.h"
|
|
|
|
|
|
typedef struct INIT_WIN_POS {
|
|
Widget ref_widget;
|
|
AB_WPOS_TYPE type;
|
|
} InitWinPos;
|
|
|
|
/*************************************************************************
|
|
** **
|
|
** Private Function Declarations **
|
|
** **
|
|
**************************************************************************/
|
|
|
|
static int format_dir_name_for_user(
|
|
STRING ugly_dir,
|
|
STRING pretty_dir,
|
|
int pretty_dir_size
|
|
);
|
|
|
|
static int format_dir_name_for_system(
|
|
STRING user_dir_name,
|
|
STRING system_dir,
|
|
int system_dir_size
|
|
);
|
|
|
|
static void set_cursor(
|
|
Widget widget,
|
|
Cursor cursor,
|
|
BOOL on
|
|
);
|
|
|
|
static void track_win_iconify(
|
|
Widget widget,
|
|
XtPointer client_data,
|
|
XEvent *event,
|
|
Boolean *cont_disp
|
|
);
|
|
static void track_win_leader_iconify(
|
|
Widget widget,
|
|
XtPointer client_data,
|
|
XEvent *event,
|
|
Boolean *cont_disp
|
|
);
|
|
static void popdown_winCB(
|
|
Widget widget,
|
|
XtPointer client_data,
|
|
XtPointer call_data
|
|
);
|
|
static void position_winCB(
|
|
Widget widget,
|
|
XtPointer client_data,
|
|
XtPointer call_data
|
|
);
|
|
static void track_win_popupCB(
|
|
Widget widget,
|
|
XtPointer client_data,
|
|
XtPointer call_data
|
|
);
|
|
static void track_win_popdownCB(
|
|
Widget widget,
|
|
XtPointer client_data,
|
|
XtPointer call_data
|
|
);
|
|
static void track_win_destroyCB(
|
|
Widget widget,
|
|
XtPointer client_data,
|
|
XtPointer call_data
|
|
);
|
|
|
|
static void set_windows_visibility(
|
|
BOOL show
|
|
);
|
|
static void set_window_objects_visibility(
|
|
BOOL show
|
|
);
|
|
|
|
static void exit_mboxCB(
|
|
Widget widget,
|
|
XtPointer client_data,
|
|
XtPointer call_data
|
|
);
|
|
|
|
static void destroy_mboxCB(
|
|
Widget widget,
|
|
XtPointer client_data,
|
|
XtPointer call_data
|
|
);
|
|
|
|
static void mwm_close_mboxCB(
|
|
Widget widget,
|
|
XtPointer client_data,
|
|
XtPointer call_data
|
|
);
|
|
|
|
/*************************************************************************
|
|
** **
|
|
** Data **
|
|
** **
|
|
**************************************************************************/
|
|
|
|
static ISTRING current_dir = NULL; /* formatted for user */
|
|
static ISTRING raw_current_dir = NULL; /* full path for system */
|
|
static STRING home_env_var_name = "HOME";
|
|
|
|
static ABWindow *AB_win_head = NULL;
|
|
static ABWindow *AB_win_tail = NULL;
|
|
static ABWindow *AB_win_leader = NULL;
|
|
|
|
static int AB_stack_offset = 50;
|
|
static int AB_frame_title_height = 25;
|
|
static int AB_frame_edge_width = 5;
|
|
static int AB_min_dimension = 20;
|
|
|
|
/*************************************************************************
|
|
** **
|
|
** Function Definitions **
|
|
** **
|
|
**************************************************************************/
|
|
|
|
void
|
|
ab_position_window(
|
|
Widget widget,
|
|
Widget ref_widget,
|
|
AB_WPOS_TYPE pos_type
|
|
)
|
|
{
|
|
Widget shell, ref_shell;
|
|
Dimension shell_w, shell_h, ref_w, ref_h;
|
|
Position shell_x, shell_y, ref_x, ref_y;
|
|
int screen_w, screen_h;
|
|
int delta_w, delta_h;
|
|
|
|
if (widget == NULL || ref_widget == NULL ||
|
|
!XtIsRealized(ref_widget))
|
|
return;
|
|
|
|
shell_w = shell_h = shell_x = shell_y = 0;
|
|
ref_w = ref_h = ref_x = ref_y = 0;
|
|
|
|
/*
|
|
* Get Shell widget-id and geometry of window and its
|
|
* reference-window
|
|
*/
|
|
shell = ui_get_ancestor_shell(widget);
|
|
XtVaGetValues(shell,
|
|
XmNwidth, &shell_w,
|
|
XmNheight, &shell_h,
|
|
NULL);
|
|
|
|
ref_shell = ui_get_ancestor_shell(ref_widget);
|
|
XtVaGetValues(ref_shell,
|
|
XmNx, &ref_x,
|
|
XmNy, &ref_y,
|
|
XmNwidth, &ref_w,
|
|
XmNheight, &ref_h,
|
|
NULL);
|
|
|
|
/*
|
|
* Adjust geometry values to accommodate window-frame
|
|
*
|
|
* Also, if this routine is called before a window's contents have
|
|
* been managed, its current available dimensions may be misleadingly
|
|
* small. If so, print out a warning in debug mode...
|
|
*/
|
|
if ((int)shell_w < AB_min_dimension || (int)shell_h < AB_min_dimension)
|
|
util_dprintf(1, "ab_position_window: %s - %dx%d - size under minimum\n",
|
|
XtName(shell), shell_w, shell_h);
|
|
|
|
shell_w += (2 * AB_frame_edge_width);
|
|
shell_h += (AB_frame_title_height + AB_frame_edge_width);
|
|
|
|
ref_y -= AB_frame_title_height;
|
|
ref_x -= AB_frame_edge_width;
|
|
ref_w += (2 * AB_frame_edge_width);
|
|
ref_h += (AB_frame_title_height + AB_frame_edge_width);
|
|
|
|
screen_w = WidthOfScreen(XtScreen(widget));
|
|
screen_h = HeightOfScreen(XtScreen(widget));
|
|
|
|
switch(pos_type)
|
|
{
|
|
case AB_WPOS_TILE_RIGHT:
|
|
shell_y = ref_y;
|
|
shell_x = ref_x + ref_w;
|
|
break;
|
|
|
|
case AB_WPOS_TILE_LEFT:
|
|
shell_y = ref_y;
|
|
shell_x = ref_x - shell_w;
|
|
break;
|
|
|
|
case AB_WPOS_TILE_HORIZONTAL:
|
|
shell_y = ref_y;
|
|
/* Determine side for best fit... */
|
|
if ((int)ref_x >= (int)(screen_w - (ref_x + ref_w)) ||
|
|
(int)shell_w <= (int)ref_x)
|
|
shell_x = ref_x - shell_w; /* TILE LEFT*/
|
|
else
|
|
shell_x = ref_x + ref_w; /* TILE RIGHT */
|
|
break;
|
|
|
|
case AB_WPOS_TILE_ABOVE:
|
|
shell_x = ref_x;
|
|
shell_y = ref_y - shell_h;
|
|
break;
|
|
|
|
case AB_WPOS_TILE_BELOW:
|
|
shell_x = ref_x;
|
|
shell_y = ref_y + ref_h;
|
|
break;
|
|
|
|
case AB_WPOS_TILE_VERTICAL:
|
|
shell_x = ref_x;
|
|
/* Determine side for best fit... */
|
|
if ((int)ref_y >= (int)(screen_h - (ref_y + ref_h)) ||
|
|
(int)shell_h <= (int)ref_y)
|
|
shell_y = ref_y - shell_h; /* TILE ABOVE */
|
|
else
|
|
shell_y = ref_y + ref_h; /* TILE_BELOW */
|
|
break;
|
|
|
|
case AB_WPOS_STACK_DIAGONAL:
|
|
shell_x = ref_x + AB_stack_offset;
|
|
shell_y = ref_y + AB_stack_offset;
|
|
break;
|
|
|
|
default:
|
|
case AB_WPOS_STACK_CENTER:
|
|
delta_w = ref_w - shell_w;
|
|
shell_x = ref_x + (delta_w/2);
|
|
|
|
delta_h = ref_h - shell_h;
|
|
shell_y = ref_y + (delta_h/2);
|
|
|
|
break;
|
|
}
|
|
|
|
XtVaSetValues(shell,
|
|
XmNx, shell_x,
|
|
XmNy, shell_y,
|
|
NULL);
|
|
}
|
|
|
|
BOOL
|
|
ab_window_leader_iconified(
|
|
)
|
|
{
|
|
return(AB_win_leader->state & WindowIconified);
|
|
}
|
|
|
|
void
|
|
ab_register_window(
|
|
Widget widget,
|
|
AB_WIN_TYPE type,
|
|
unsigned long init_state,
|
|
Widget init_pos_ref_widget,
|
|
AB_WPOS_TYPE init_pos_type,
|
|
XtCallbackProc close_callback,
|
|
XtPointer close_clientdata
|
|
)
|
|
{
|
|
ABWindow *newwin;
|
|
InitWinPos *init_pos;
|
|
Widget shell = ui_get_ancestor_shell(widget);
|
|
|
|
newwin = (ABWindow*)util_malloc(sizeof(ABWindow));
|
|
newwin->widget = widget;
|
|
newwin->type = type;
|
|
newwin->state = init_state;
|
|
newwin->next = NULL;
|
|
|
|
/*
|
|
* Install a Window close callback and ensure the deleteResponse
|
|
* gets set to XmDO_NOTHING (to prevent automatic unmanaging of the
|
|
* shell's first child).
|
|
* Use parameter callback if specified, else use default which just
|
|
* pops the window down.
|
|
*/
|
|
ui_add_window_close_callback(shell,
|
|
close_callback? close_callback : popdown_winCB,
|
|
close_callback? close_clientdata : NULL,
|
|
XmDO_NOTHING);
|
|
|
|
if (type == AB_WIN_LEADER)
|
|
{
|
|
/* The Window leader is stored separately */
|
|
if (AB_win_leader == NULL)
|
|
{
|
|
AB_win_leader = newwin;
|
|
ui_add_window_iconify_handler(shell,
|
|
track_win_leader_iconify, (XtPointer)newwin);
|
|
return;
|
|
}
|
|
else
|
|
util_dprintf(1, "ab_register_window: can only have 1 Window Leader\n");
|
|
}
|
|
|
|
/*
|
|
* Append new Win Record onto linked-list
|
|
*/
|
|
if (AB_win_head == NULL) /* first one */
|
|
AB_win_head = AB_win_tail = newwin;
|
|
else
|
|
{
|
|
AB_win_tail->next = newwin;
|
|
AB_win_tail = newwin;
|
|
}
|
|
|
|
/*
|
|
* Set up handlers to track window behavior
|
|
*/
|
|
if (type == AB_WIN_WINDOW)
|
|
ui_add_window_iconify_handler(shell,
|
|
track_win_iconify, (XtPointer)newwin);
|
|
|
|
XtAddCallback(shell, XtNpopupCallback, track_win_popupCB,
|
|
(XtPointer)newwin);
|
|
XtAddCallback(shell, XtNpopdownCallback, track_win_popdownCB,
|
|
(XtPointer)newwin);
|
|
XtAddCallback(shell, XtNdestroyCallback, track_win_destroyCB,
|
|
(XtPointer)newwin);
|
|
|
|
/*
|
|
* Set up general window resources to get popup/popdown to work correctly
|
|
* We will not be using Motif's method of Managing the first child of the
|
|
* shell to get the window to popup!
|
|
*/
|
|
XtSetMappedWhenManaged(shell, False);
|
|
XtManageChild(widget);
|
|
if (init_pos_type != AB_WPOS_UNSPECIFIED)
|
|
{
|
|
init_pos = (InitWinPos*)util_malloc(sizeof(InitWinPos));
|
|
init_pos->ref_widget = init_pos_ref_widget;
|
|
init_pos->type = init_pos_type;
|
|
XtAddCallback(shell, XtNpopupCallback, position_winCB,
|
|
(XtPointer)init_pos);
|
|
}
|
|
}
|
|
|
|
void
|
|
ab_show_window(
|
|
Widget widget
|
|
)
|
|
{
|
|
ABWindow *win;
|
|
|
|
for(win = AB_win_head; win != NULL; win = win->next)
|
|
{
|
|
if (win->widget == widget)
|
|
{
|
|
if (win->state & WindowUp)
|
|
{
|
|
if (win->state & WindowIconified &&
|
|
!(AB_win_leader->state & WindowIconified))
|
|
{
|
|
/* Window is iconified, unmap it so we can change its
|
|
* initial state and remap it as Opened
|
|
*/
|
|
ui_win_show(widget, False, XtGrabNone);
|
|
}
|
|
else /* Window is already Open */
|
|
{
|
|
ui_win_front(win->widget);
|
|
}
|
|
}
|
|
/* Popup Window */
|
|
XtSetMappedWhenManaged(ui_get_ancestor_shell(win->widget), True);
|
|
switch(win->type)
|
|
{
|
|
case AB_WIN_MODAL:
|
|
ui_win_show(win->widget, True, XtGrabExclusive);
|
|
break;
|
|
default:
|
|
ui_win_show(win->widget, True, XtGrabNone);
|
|
break;
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
|
|
util_dprintf(1, "ab_show_window: %s is not a registered window\n",
|
|
XtName(widget));
|
|
}
|
|
|
|
BOOL
|
|
ab_window_is_open(
|
|
Widget widget
|
|
)
|
|
{
|
|
ABWindow *win;
|
|
|
|
for(win = AB_win_head; win != NULL; win = win->next)
|
|
{
|
|
if (win->widget == widget)
|
|
return((win->state & WindowUp) &&
|
|
!(win->state & WindowIconified));
|
|
}
|
|
util_dprintf(1, "ab_window_is_open: %s is not a registered window\n",
|
|
XtName(widget));
|
|
|
|
return False;
|
|
}
|
|
|
|
static void
|
|
track_win_leader_iconify(
|
|
Widget widget,
|
|
XtPointer client_data,
|
|
XEvent *event,
|
|
Boolean *cont_dispatch
|
|
)
|
|
{
|
|
switch (event->type)
|
|
{
|
|
case MapNotify: /* Leader Window Opened */
|
|
AB_win_leader->state &= (~WindowIconified);
|
|
if (InBuildMode)
|
|
{
|
|
/*
|
|
** Order is important. Objects need to be first. Modal
|
|
** dialogs can be parented off of main windows. If the
|
|
** parent is not mapped first, the dialog loses it's
|
|
** modality.
|
|
*/
|
|
set_window_objects_visibility(True);
|
|
set_windows_visibility(True);
|
|
}
|
|
break;
|
|
|
|
case UnmapNotify: /* Leader Window Iconified */
|
|
AB_win_leader->state |= WindowIconified;
|
|
if (InBuildMode)
|
|
{
|
|
set_windows_visibility(False);
|
|
set_window_objects_visibility(False);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
track_win_iconify(
|
|
Widget widget,
|
|
XtPointer client_data,
|
|
XEvent *event,
|
|
Boolean *cont_disp
|
|
)
|
|
{
|
|
ABWindow *win = (ABWindow*)client_data;
|
|
|
|
switch (event->type)
|
|
{
|
|
case MapNotify:
|
|
if (InBuildMode &&
|
|
win->state & WindowIconified &&
|
|
!(AB_win_leader->state & WindowIconified))
|
|
{
|
|
win->state &= (~WindowIconified);
|
|
XtVaSetValues(widget, XtNinitialState, NormalState, NULL);
|
|
}
|
|
break;
|
|
case UnmapNotify:
|
|
/*
|
|
* We can detect that the window has been iconified
|
|
* (not popped-down) because the track_win_popdownCB
|
|
* was not called (so WindowUp is still set).
|
|
*
|
|
* Note: XtNiconic is not being used because it doesn't
|
|
* reflect the current state of the window (Xt bug??)
|
|
*/
|
|
if (InBuildMode &&
|
|
win->state & WindowUp &&
|
|
!(win->state & WindowIconified) &&
|
|
!(AB_win_leader->state & WindowIconified))
|
|
{
|
|
win->state |= WindowIconified;
|
|
XtVaSetValues(widget, XtNinitialState, IconicState, NULL);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
popdown_winCB(
|
|
Widget shell,
|
|
XtPointer client_data,
|
|
XtPointer call_data
|
|
)
|
|
{
|
|
ui_win_show(shell, False, XtGrabNone);
|
|
}
|
|
|
|
static void
|
|
position_winCB(
|
|
Widget shell,
|
|
XtPointer client_data,
|
|
XtPointer call_data
|
|
)
|
|
{
|
|
InitWinPos *init_pos = (InitWinPos*)client_data;
|
|
|
|
ab_position_window(shell, init_pos->ref_widget, init_pos->type);
|
|
|
|
/* We only position the window the first time it is invoked; after
|
|
* this, the user is in control, so remove this callback and destroy
|
|
* the init data.
|
|
*/
|
|
XtRemoveCallback(shell, XtNpopupCallback, position_winCB, client_data);
|
|
util_free(init_pos);
|
|
}
|
|
|
|
static void
|
|
track_win_popupCB(
|
|
Widget shell,
|
|
XtPointer client_data,
|
|
XtPointer call_data
|
|
)
|
|
{
|
|
ABWindow *win = (ABWindow*)client_data;
|
|
win->state |= WindowUp;
|
|
}
|
|
|
|
static void
|
|
track_win_popdownCB(
|
|
Widget shell,
|
|
XtPointer client_data,
|
|
XtPointer call_data
|
|
)
|
|
{
|
|
ABWindow *win = (ABWindow*)client_data;
|
|
|
|
if (InBuildMode &&
|
|
!(AB_win_leader->state & WindowIconified))
|
|
{
|
|
win->state &= (~WindowUp);
|
|
if (win->state & WindowIconified)
|
|
{
|
|
XtVaSetValues(shell, XtNinitialState, NormalState, NULL);
|
|
win->state &= (~WindowIconified);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
track_win_destroyCB(
|
|
Widget shell,
|
|
XtPointer client_data,
|
|
XtPointer call_data
|
|
)
|
|
{
|
|
ABWindow *win = (ABWindow*)client_data;
|
|
ABWindow *prev = NULL;
|
|
ABWindow *p;
|
|
|
|
/*
|
|
* Adjust linked-list for removal of Window
|
|
*/
|
|
if (AB_win_head == win)
|
|
AB_win_head = win->next;
|
|
else
|
|
{
|
|
/* Find previous window in linked-list */
|
|
p = AB_win_head;
|
|
while (p != win)
|
|
{
|
|
prev = p;
|
|
p = p->next;
|
|
}
|
|
prev->next = win->next;
|
|
|
|
if (AB_win_tail == win)
|
|
AB_win_tail = prev;
|
|
}
|
|
|
|
/*
|
|
* Remove all tracker routines, and free Win record
|
|
*/
|
|
if (win->type == AB_WIN_WINDOW)
|
|
ui_remove_window_iconify_handler(shell, track_win_iconify,
|
|
(XtPointer)win);
|
|
XtRemoveCallback(shell, XtNpopupCallback, track_win_popupCB,
|
|
(XtPointer)win);
|
|
XtRemoveCallback(shell, XtNpopdownCallback, track_win_popdownCB,
|
|
(XtPointer)win);
|
|
|
|
util_free(win);
|
|
|
|
}
|
|
|
|
static void
|
|
set_windows_visibility(
|
|
BOOL show
|
|
)
|
|
{
|
|
ABWindow *win;
|
|
|
|
for(win = AB_win_head; win != NULL; win = win->next)
|
|
{
|
|
if (win->state & WindowUp)
|
|
{
|
|
switch(win->type)
|
|
{
|
|
case AB_WIN_MODAL:
|
|
ui_win_show(win->widget, show, XtGrabExclusive);
|
|
break;
|
|
|
|
default:
|
|
ui_win_show(win->widget, show, XtGrabNone);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
ab_takedown_windows(
|
|
)
|
|
{
|
|
set_windows_visibility(False);
|
|
}
|
|
|
|
void
|
|
ab_putback_windows(
|
|
)
|
|
{
|
|
set_windows_visibility(True);
|
|
}
|
|
|
|
static void
|
|
set_window_objects_visibility(
|
|
BOOL show
|
|
)
|
|
{
|
|
AB_TRAVERSAL trav;
|
|
ABObj project = proj_get_project();
|
|
ABObj winobj;
|
|
|
|
for (trav_open(&trav, project, AB_TRAV_WINDOWS);
|
|
(winobj = trav_next(&trav)) != NULL; )
|
|
{
|
|
if (obj_is_base_win(winobj) &&
|
|
obj_has_flag(winobj, MappedFlag))
|
|
ui_win_show(objxm_get_widget(winobj), show, XtGrabNone);
|
|
}
|
|
trav_close(&trav);
|
|
}
|
|
|
|
|
|
int
|
|
ab_update_stat_region(
|
|
AB_STATUS_INFO type,
|
|
String value
|
|
)
|
|
{
|
|
static Widget obj_type = NULL;
|
|
static Widget obj_name = NULL;
|
|
static Widget obj_pos = NULL;
|
|
static Widget obj_size = NULL;
|
|
static Widget curs_pos = NULL;
|
|
static Widget cur_module = NULL;
|
|
Widget widget = NULL;
|
|
String nullstr = " ";
|
|
|
|
switch(type)
|
|
{
|
|
case AB_STATUS_OBJ_TYPE:
|
|
if (obj_type == NULL)
|
|
obj_type = dtb_palette_ab_palette_main.object_type_field;
|
|
widget = obj_type;
|
|
break;
|
|
case AB_STATUS_OBJ_NAME:
|
|
if (obj_name == NULL)
|
|
obj_name = dtb_palette_ab_palette_main.object_name_field;
|
|
widget = obj_name;
|
|
break;
|
|
case AB_STATUS_OBJ_POS:
|
|
if (obj_pos == NULL)
|
|
obj_pos = dtb_palette_ab_palette_main.position_field;
|
|
widget = obj_pos;
|
|
break;
|
|
case AB_STATUS_OBJ_SIZE:
|
|
if (obj_size == NULL)
|
|
obj_size = dtb_palette_ab_palette_main.size_field;
|
|
widget = obj_size;
|
|
break;
|
|
case AB_STATUS_CURS_POS:
|
|
if (curs_pos == NULL)
|
|
curs_pos = dtb_palette_ab_palette_main.cursor_position_field;
|
|
widget = curs_pos;
|
|
break;
|
|
case AB_STATUS_CUR_MODULE:
|
|
if (cur_module == NULL)
|
|
cur_module = dtb_palette_ab_palette_main.editing_module_field;
|
|
|
|
widget = cur_module;
|
|
if (value == NULL)
|
|
value = "( None )";
|
|
}
|
|
if (value == NULL)
|
|
value = nullstr;
|
|
|
|
/* Update the footer to display the current object-type */
|
|
if (widget != NULL)
|
|
XtVaSetValues(widget,
|
|
XtVaTypedArg, XmNlabelString, XtRString,
|
|
value, strlen(value)+1,
|
|
NULL);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Set the busy-cursor ON or OFF on all AB Windows
|
|
*/
|
|
void
|
|
ab_set_busy_cursor(
|
|
BOOL on
|
|
)
|
|
{
|
|
AB_TRAVERSAL trav;
|
|
ABObj project = proj_get_project();
|
|
ABWindow *win;
|
|
ABObj module;
|
|
ABObj winobj;
|
|
static Cursor busy_cursor = 0;
|
|
Cursor new_cursor = 0;
|
|
int num_wins;
|
|
int i;
|
|
|
|
if (busy_cursor == 0)
|
|
busy_cursor = XCreateFontCursor(XtDisplay(AB_toplevel), XC_watch);
|
|
|
|
if (on)
|
|
new_cursor = busy_cursor;
|
|
|
|
set_cursor(AB_toplevel, new_cursor, on);
|
|
|
|
/*
|
|
* Loop through Windows and set cursor on any that
|
|
* are currently UP
|
|
*/
|
|
for(win = AB_win_head; win != NULL; win = win->next)
|
|
{
|
|
if (win->state & WindowUp)
|
|
set_cursor(win->widget, new_cursor, on);
|
|
}
|
|
|
|
/* Set busy cursor for any AB windows currently up */
|
|
for (trav_open(&trav, project, AB_TRAV_MODULES);
|
|
(module = trav_next(&trav)) != NULL; )
|
|
{
|
|
num_wins = obj_get_num_children(module);
|
|
for (i = 0; i < num_wins; i++)
|
|
{
|
|
winobj = obj_get_child(module, i);
|
|
if (obj_is_window(winobj) && winobj->ui_handle != NULL)
|
|
set_cursor((Widget)winobj->ui_handle, new_cursor, on);
|
|
}
|
|
}
|
|
trav_close(&trav);
|
|
}
|
|
|
|
|
|
/*
|
|
* This function is used as a callback for libABobjXm. Currently, it
|
|
* only calls a dtb_ function, but if the dtb_functions change, or
|
|
* we need to do more, here, we won't have to modify libABobjXm.
|
|
*/
|
|
int
|
|
ab_cvt_image_file_to_pixmap(
|
|
Widget widget,
|
|
STRING file_name,
|
|
Pixmap *pixmap_out
|
|
)
|
|
{
|
|
return dtb_cvt_image_file_to_pixmap(widget, file_name, pixmap_out);
|
|
}
|
|
|
|
/*
|
|
* This function is the post instantiate callback for libABobjXm. Currently, it
|
|
* only calls the group layout function, but if we need to do more here,
|
|
* we won't have to modify libABobjXm.
|
|
*/
|
|
int
|
|
ab_post_instantiate(
|
|
ABObj obj
|
|
)
|
|
{
|
|
if (obj && obj_is_group(obj) && (obj_get_group_type(obj) != AB_GROUP_IGNORE))
|
|
{
|
|
Widget group_w;
|
|
|
|
abobj_disable_save_needed();
|
|
|
|
abobj_layout_group(obj, TRUE);
|
|
|
|
group_w = objxm_get_widget(obj);
|
|
|
|
/*
|
|
* Register expose handler
|
|
* Some group objects depend on it's members' sizes for their layout.
|
|
* Unfortunately, some group members have invalid sizes prior to
|
|
* XtRealize(), so the group layout has to be recalculated after the
|
|
* group is realized or exposed in this case, since there is no realize
|
|
* callback.
|
|
*/
|
|
if (group_w)
|
|
{
|
|
ABObj parent = NULL;
|
|
Widget parent_w = NULL;
|
|
|
|
/*
|
|
* Get (root) parent ABObj
|
|
*/
|
|
parent = obj_get_parent(obj);
|
|
|
|
if (parent)
|
|
parent = obj_get_root(parent);
|
|
|
|
/*
|
|
* Get parent widget
|
|
*/
|
|
if (parent)
|
|
parent_w = objxm_get_widget(parent);
|
|
|
|
if (parent_w)
|
|
{
|
|
/*
|
|
* If parent widget is not realized, register expose handler
|
|
*/
|
|
if (!XtIsRealized(parent_w))
|
|
abobj_register_group_expose_handler(obj);
|
|
}
|
|
}
|
|
|
|
abobj_enable_save_needed();
|
|
}
|
|
|
|
return (0);
|
|
}
|
|
|
|
|
|
/*
|
|
* Accepts NULL and "" as valid directories ( == "." )
|
|
*/
|
|
int
|
|
ab_change_dir(STRING request_dir)
|
|
{
|
|
char pretty_dir[MAXPATHLEN+1];
|
|
BOOL dir_changed = TRUE; /* if path string changed */
|
|
BOOL force_update = FALSE;
|
|
*pretty_dir = 0;
|
|
|
|
/*
|
|
* Determine the new directory
|
|
*/
|
|
if (current_dir == NULL)
|
|
{
|
|
ab_get_cur_dir(); /* initialize it! */
|
|
}
|
|
if (request_dir == NULL)
|
|
{
|
|
dir_changed = FALSE;
|
|
force_update = TRUE;
|
|
request_dir = istr_string(raw_current_dir);
|
|
}
|
|
else
|
|
{
|
|
/* see if the path we present to the user will change because of
|
|
* this.
|
|
*/
|
|
if (format_dir_name_for_user(request_dir, pretty_dir, MAXPATHLEN) >= 0)
|
|
{
|
|
dir_changed = !(istr_equalstr(current_dir, pretty_dir));
|
|
}
|
|
}
|
|
|
|
/*
|
|
* See if any work actually needs to be done
|
|
*/
|
|
if ((!dir_changed) && (!force_update))
|
|
{
|
|
/* no action necessary */
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Actually change directories and update info
|
|
*/
|
|
if (dir_changed)
|
|
{
|
|
{
|
|
char sys_dir[MAXPATHLEN+1];
|
|
if (format_dir_name_for_system(
|
|
request_dir, sys_dir, MAXPATHLEN+1) >= 0)
|
|
{
|
|
/*
|
|
* We may have changed paths but still be in the same actual
|
|
* directory. Only chdir if we've actually moved.
|
|
*/
|
|
if (!util_paths_are_same_file(".", sys_dir))
|
|
{
|
|
if (chdir(sys_dir) != 0)
|
|
{
|
|
return -1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if ((*pretty_dir) == 0) /* we may have done this above */
|
|
{
|
|
format_dir_name_for_user(request_dir, pretty_dir, MAXPATHLEN);
|
|
}
|
|
istr_destroy(raw_current_dir);
|
|
raw_current_dir = istr_create(request_dir);
|
|
istr_destroy(current_dir);
|
|
current_dir = istr_create(pretty_dir);
|
|
}
|
|
|
|
/*
|
|
* Update other subsystems.
|
|
*/
|
|
cgen_notify_new_directory(istr_string(current_dir));
|
|
|
|
return 0;
|
|
}
|
|
|
|
BOOL
|
|
ab_is_cur_dir(STRING dir)
|
|
{
|
|
char pretty_dir[MAXPATHLEN];
|
|
BOOL is_cur_dir= FALSE;
|
|
*pretty_dir = 0;
|
|
|
|
if (current_dir == NULL)
|
|
{
|
|
ab_get_cur_dir(); /* initialize it! */
|
|
}
|
|
|
|
if ((dir == NULL) || (*dir == 0) || (*dir == '.'))
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
format_dir_name_for_user(dir, pretty_dir, MAXPATHLEN);
|
|
is_cur_dir = istr_equalstr(current_dir, pretty_dir);
|
|
|
|
return is_cur_dir;
|
|
}
|
|
|
|
|
|
STRING
|
|
ab_get_cur_dir(void)
|
|
{
|
|
static BOOL initialized = FALSE;
|
|
char formatted_cur_dir[MAXPATHLEN];
|
|
char cur_dir[MAXPATHLEN];
|
|
STRING new_raw_dir = NULL;
|
|
STRING new_dir = NULL;
|
|
*formatted_cur_dir = 0;
|
|
*cur_dir = 0;
|
|
|
|
if ( initialized &&
|
|
(raw_current_dir != NULL) &&
|
|
util_paths_are_same_file(istr_string(raw_current_dir), ".") )
|
|
{
|
|
goto epilogue; /* no change */
|
|
}
|
|
|
|
/*
|
|
* Get the raw current directory
|
|
*/
|
|
new_raw_dir = NULL;
|
|
if (!initialized)
|
|
{
|
|
initialized = TRUE;
|
|
new_raw_dir = getenv("PWD");
|
|
}
|
|
if (new_raw_dir == NULL)
|
|
{
|
|
if (getcwd(cur_dir, MAXPATHLEN) != NULL)
|
|
{
|
|
new_raw_dir = cur_dir;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Get the pretty version of the current directory
|
|
*/
|
|
if (new_raw_dir == NULL)
|
|
{
|
|
new_raw_dir = ".";
|
|
new_dir = "* Indeterminable *";
|
|
}
|
|
else
|
|
{
|
|
format_dir_name_for_user(new_raw_dir, formatted_cur_dir, MAXPATHLEN);
|
|
new_dir = formatted_cur_dir;
|
|
}
|
|
|
|
istr_destroy(current_dir);
|
|
istr_destroy(raw_current_dir);
|
|
|
|
current_dir = istr_create(new_dir);
|
|
raw_current_dir = istr_create(new_raw_dir);
|
|
|
|
epilogue:
|
|
return istr_string(current_dir);
|
|
}
|
|
|
|
/*
|
|
* Takes a directory name and formats it so that it will look good
|
|
* to the user.
|
|
* Guarantees: no trailing slashes (except for / directory)
|
|
*/
|
|
static int
|
|
format_dir_name_for_user(
|
|
STRING ugly_dir,
|
|
STRING pretty_dir,
|
|
int pretty_dir_size
|
|
)
|
|
{
|
|
STRING home= getenv(home_env_var_name);
|
|
int home_name_len = 0;
|
|
int i= 0;
|
|
|
|
if (home != NULL)
|
|
{
|
|
char home_relative[MAXPATHLEN];
|
|
home_name_len = strlen(home);
|
|
*home_relative = 0;
|
|
|
|
util_cvt_path_to_relative(ugly_dir, home, home_relative, MAXPATHLEN);
|
|
*pretty_dir = 0;
|
|
if (home_relative[0] == '/')
|
|
{
|
|
strncpy(pretty_dir, home_relative, pretty_dir_size);
|
|
pretty_dir[pretty_dir_size-1]= 0;
|
|
}
|
|
else
|
|
{
|
|
/* relative to home (but avoid "~/." if actually in home dir)*/
|
|
strcpy(pretty_dir, "~");
|
|
if (!util_streq(home_relative, "."))
|
|
{
|
|
strcat(pretty_dir, "/");
|
|
strncat(pretty_dir, home_relative, pretty_dir_size-2);
|
|
}
|
|
pretty_dir[pretty_dir_size-1]= 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
strncpy(pretty_dir, ugly_dir, pretty_dir_size);
|
|
pretty_dir[pretty_dir_size-1]= 0;
|
|
}
|
|
|
|
/*
|
|
* strip trailing slashes
|
|
*/
|
|
for (i= strlen(pretty_dir)-1; i > 0; --i)
|
|
{
|
|
if (pretty_dir[i] == '/')
|
|
{
|
|
pretty_dir[i]= 0;
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
util_dprintf(2,"user format dir '%s' -> '%s'\n", ugly_dir, pretty_dir);
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
* Takes a directory name that may or may not be formatted to look
|
|
* good to the user, and converts it to a path that will work with
|
|
* chdir().
|
|
*/
|
|
static int
|
|
format_dir_name_for_system(
|
|
STRING user_dir_name,
|
|
STRING system_dir,
|
|
int system_dir_size
|
|
)
|
|
{
|
|
int return_value = 0;
|
|
char *user_dir_ptr = user_dir_name;
|
|
STRING homeVar = NULL;
|
|
*system_dir = 0;
|
|
if (util_strempty(user_dir_name))
|
|
{
|
|
goto epilogue;
|
|
}
|
|
|
|
if (user_dir_name[0] == '~')
|
|
{
|
|
if ((homeVar = getenv(home_env_var_name)) != NULL)
|
|
{
|
|
util_strncpy(system_dir, homeVar, system_dir_size);
|
|
++user_dir_ptr;
|
|
}
|
|
if ((*user_dir_ptr) == '/')
|
|
{
|
|
strcat(system_dir, "/");
|
|
++user_dir_ptr;
|
|
}
|
|
}
|
|
|
|
strcat(system_dir, user_dir_ptr);
|
|
|
|
epilogue:
|
|
util_dprintf(2,"sys format dir '%s' -> '%s'\n", user_dir_name, system_dir);
|
|
return return_value;
|
|
}
|
|
|
|
|
|
static void
|
|
set_cursor(
|
|
Widget widget,
|
|
Cursor cursor,
|
|
BOOL on
|
|
)
|
|
{
|
|
Window win;
|
|
Display *dpy;
|
|
|
|
if (widget && XtIsRealized(widget))
|
|
{
|
|
dpy = XtDisplay(widget);
|
|
win = XtWindow(widget);
|
|
if (on)
|
|
XDefineCursor(dpy, win, cursor);
|
|
else
|
|
XUndefineCursor(dpy, win);
|
|
}
|
|
}
|
|
|
|
void
|
|
ab_palette_set_active(
|
|
BOOL active
|
|
)
|
|
{
|
|
static Widget palette_cpanel = NULL;
|
|
static Widget palette_footer = NULL;
|
|
/* REMIND andy: take out when working */
|
|
|
|
if (palette_cpanel == NULL)
|
|
{
|
|
palette_cpanel = dtb_palette_ab_palette_main.palette_cpanel;
|
|
palette_footer = dtb_palette_ab_palette_main.palette_footer;
|
|
}
|
|
|
|
ui_set_active(palette_cpanel, active);
|
|
ui_set_active(palette_footer, active);
|
|
}
|
|
|
|
void
|
|
ab_exit_dtbuilder()
|
|
{
|
|
static DTB_MODAL_ANSWER answer;
|
|
XtAppContext app;
|
|
static BOOL Up = False;
|
|
Widget dlg = (Widget) NULL;
|
|
Widget shell = (Widget) NULL;
|
|
Widget mbox = (Widget) NULL;
|
|
Arg args[10];
|
|
int n = 0;
|
|
|
|
answer = DTB_ANSWER_NONE;
|
|
if ( !Up )
|
|
{
|
|
if (proj_check_unsaved_edits(proj_get_project()))
|
|
{
|
|
Up = True;
|
|
|
|
dtb_palette_exit_msg_initialize(&dtb_palette_exit_msg);
|
|
|
|
if (ab_window_leader_iconified())
|
|
{
|
|
shell = XtCreatePopupShell("exit_dtbuilder",
|
|
topLevelShellWidgetClass,
|
|
dtb_get_toplevel_widget(),
|
|
(ArgList) NULL, (Cardinal) 0);
|
|
|
|
n = 0;
|
|
XtSetArg(args[n], XmNdialogType,
|
|
dtb_palette_exit_msg.type); n++;
|
|
XtSetArg(args[n], XmNmessageString,
|
|
dtb_palette_exit_msg.message); n++;
|
|
XtSetArg(args[n], XmNdialogTitle,
|
|
dtb_palette_exit_msg.title); n++;
|
|
XtSetArg(args[n], XmNokLabelString,
|
|
dtb_palette_exit_msg.action1_label); n++;
|
|
XtSetArg(args[n], XmNdefaultButtonType,
|
|
XmDIALOG_CANCEL_BUTTON); n++;
|
|
XtSetArg(args[n], XmNuserData, &answer); n++;
|
|
mbox = XmCreateMessageBox(shell, "exit_mbox", args, n);
|
|
XtManageChild(mbox);
|
|
|
|
XtAddCallback(mbox, XmNokCallback, exit_mboxCB,
|
|
(XtPointer) DTB_ANSWER_ACTION1);
|
|
XtAddCallback(mbox, XmNcancelCallback, exit_mboxCB,
|
|
(XtPointer) DTB_ANSWER_CANCEL);
|
|
XtAddCallback(shell, XmNpopdownCallback, destroy_mboxCB,
|
|
(XtPointer) NULL);
|
|
|
|
ui_add_window_close_callback(shell, mwm_close_mboxCB,
|
|
(XtPointer) &answer, XmDO_NOTHING);
|
|
|
|
XtRealizeWidget(shell);
|
|
XtPopup(shell, XtGrabExclusive);
|
|
|
|
ui_win_front(shell);
|
|
app = XtDisplayToApplicationContext(XtDisplay(mbox));
|
|
while (answer == DTB_ANSWER_NONE)
|
|
{
|
|
XtAppProcessEvent(app, XtIMAll);
|
|
}
|
|
}
|
|
else if (shell == NULL)
|
|
{
|
|
/* Display the "unsaved edits" message DIALOG if the
|
|
* "unsaved edits" message topLevelShell is not already
|
|
* up.
|
|
*/
|
|
answer = dtb_show_modal_message(dtb_get_toplevel_widget(),
|
|
&dtb_palette_exit_msg, NULL, NULL, &dlg);
|
|
}
|
|
|
|
switch (answer)
|
|
{
|
|
case DTB_ANSWER_ACTION1:
|
|
exit(0);
|
|
case DTB_ANSWER_CANCEL:
|
|
break;
|
|
}
|
|
Up = False;
|
|
}
|
|
else
|
|
{
|
|
exit(0);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (dlg != NULL)
|
|
ui_win_front(dlg);
|
|
else if (shell != NULL)
|
|
ui_win_front(shell);
|
|
}
|
|
}
|
|
|
|
static void
|
|
exit_mboxCB(
|
|
Widget widget,
|
|
XtPointer client_data,
|
|
XtPointer call_data
|
|
)
|
|
{
|
|
DTB_MODAL_ANSWER op = (DTB_MODAL_ANSWER) client_data;
|
|
DTB_MODAL_ANSWER *answerp = NULL;
|
|
|
|
XtVaGetValues(widget, XmNuserData, &answerp, NULL);
|
|
|
|
/* Dismiss the "unsaved edits" message. */
|
|
XtPopdown(ui_get_ancestor_shell(widget));
|
|
|
|
*answerp = op;
|
|
}
|
|
|
|
/*
|
|
* popdownCallback for Exit MessageBox.
|
|
*/
|
|
static void
|
|
destroy_mboxCB(
|
|
Widget widget,
|
|
XtPointer client_data,
|
|
XtPointer call_data
|
|
)
|
|
{
|
|
XtDestroyWidget(widget);
|
|
}
|
|
|
|
static void
|
|
mwm_close_mboxCB(
|
|
Widget widget,
|
|
XtPointer client_data,
|
|
XtPointer call_data
|
|
)
|
|
{
|
|
DTB_MODAL_ANSWER *op = (DTB_MODAL_ANSWER *) client_data;
|
|
|
|
/* Dismiss the "unsaved edits" message. */
|
|
XtPopdown(widget);
|
|
|
|
*op = DTB_ANSWER_CANCEL;
|
|
}
|