88cfa4d4cb
Files correlati : xi.dll Ricompilazione Demo : [ ] Commento : Aggiunto supporto per group box con spigoli smussati git-svn-id: svn://10.65.10.50/trunk@18129 c028cbd2-c16b-5b4b-a496-9718f37d4682
5848 lines
149 KiB
C
Executable File
5848 lines
149 KiB
C
Executable File
|
|
/*******************************************************************************
|
|
* Copyright 1991-1996 by ORCA Software, Inc. *
|
|
* *
|
|
* All rights reserved. May not be reproduced or distributed, in printed or *
|
|
* electronic form, without permission of ORCA Software, Inc. May not be *
|
|
* distributed as object code, separately or linked with other object modules, *
|
|
* without permission. *
|
|
*******************************************************************************/
|
|
|
|
#define XIN_INTERNAL_WINDOW
|
|
#define XIN_INTERNAL_FONT
|
|
#define XIN_INTERNAL_BITMAP
|
|
#define XIN_INTERNAL_PRINT_RECORD
|
|
|
|
#define XVT_INCL_NATIVE
|
|
#include "xvt.h"
|
|
#include "xi.h"
|
|
#include "xiport2.h"
|
|
#include "stdarg.h"
|
|
|
|
#if XIWS == XIWS_WIN
|
|
#include <commdlg.h>
|
|
#include <direct.h>
|
|
#endif
|
|
|
|
#if XIWS == XIWS_PM
|
|
#include <direct.h>
|
|
#endif
|
|
|
|
#if XIWS == XIWS_WM || XIWS == XIWS_XM || XIWS == XIWS_WXGTK
|
|
#define COALESCE_UPDATES
|
|
#endif
|
|
|
|
#define XIN_CARET_WIDTH 1
|
|
|
|
#define MEMCLEAR( x ) memset(( char* )&( x ), '\0', ( size_t )sizeof( x ))
|
|
|
|
/* We are forced to cast for XVT windows */
|
|
struct s_XinWindow
|
|
{
|
|
int dummy;
|
|
};
|
|
|
|
struct s_XinFont
|
|
{
|
|
/* Set in the XVT font convert, checked in compare since other values won't
|
|
* be set, just the xvt_fntid */
|
|
BOOLEAN from_xvt_font;
|
|
BOOLEAN bold;
|
|
BOOLEAN italic;
|
|
XinFontFamily family;
|
|
int size;
|
|
XVT_FNTID xvt_fntid;
|
|
};
|
|
|
|
struct s_XinBitmap
|
|
{
|
|
XVT_IMAGE image;
|
|
};
|
|
|
|
/* We are forced to cast for XVT print record */
|
|
struct s_XinPrintRecord
|
|
{
|
|
int dummy;
|
|
};
|
|
|
|
#ifdef COALESCE_UPDATES
|
|
typedef struct
|
|
{
|
|
int coalescing;
|
|
BOOLEAN invalidated;
|
|
XinRect inv_rct;
|
|
} XinCoalesceData;
|
|
|
|
#endif
|
|
|
|
|
|
typedef struct s_window_info
|
|
{
|
|
WINDOW win;
|
|
XinWindowEventHandler event_handler;
|
|
XinWindow prev_modal;
|
|
#ifdef COALESCE_UPDATES
|
|
XinCoalesceData coalesce;
|
|
#endif
|
|
} WindowInfo;
|
|
|
|
static WindowInfo *window_list;
|
|
static int nbr_windows;
|
|
static EVENT *cur_xvt_event;
|
|
|
|
static XinWindow xin_modal_win;
|
|
static XinWindow xin_autoclose_win;
|
|
static BOOLEAN app_terminating;
|
|
static XinMenu *xin_finish_create_menu = NULL;
|
|
static XinWindowDef *xin_finish_create_def = NULL;
|
|
XVT_PALETTE xin_palette = NULL;
|
|
|
|
XinWindowEventHandler xin_teh;
|
|
char *xin_buffer = NULL;
|
|
BOOLEAN xin_xvt_initialized = FALSE;
|
|
|
|
void XinWindowCreateFinish( XinWindow win );
|
|
|
|
static void
|
|
realloc_array( void **ptr, int nbr, size_t sz )
|
|
{
|
|
BOOLEAN is_zero = ( nbr * sz ) == 0;
|
|
|
|
if ( !*ptr )
|
|
{
|
|
if ( is_zero )
|
|
*ptr = NULL;
|
|
else
|
|
*ptr = ( void * ) XinMemoryAlloc( nbr * sz );
|
|
}
|
|
else
|
|
{
|
|
if ( is_zero )
|
|
{
|
|
XinMemoryFree( *ptr );
|
|
*ptr = NULL;
|
|
}
|
|
else
|
|
*ptr = ( void * ) XinMemoryRealloc( *ptr, nbr * sz );
|
|
}
|
|
}
|
|
|
|
void
|
|
XinXvtWindowRegister( XinWindow win, XinWindowEventHandler EventHandler )
|
|
{
|
|
WindowInfo *info;
|
|
|
|
++nbr_windows;
|
|
realloc_array( ( void ** ) &window_list, nbr_windows, sizeof( WindowInfo ) );
|
|
info = window_list + ( nbr_windows - 1 );
|
|
info->win = ( WINDOW ) win;
|
|
info->event_handler = EventHandler;
|
|
info->prev_modal = XI_NULL_WINDOW;
|
|
#ifdef COALESCE_UPDATES
|
|
info->coalesce.coalescing = 0;
|
|
#endif
|
|
}
|
|
|
|
static WindowInfo *
|
|
find_window_info( WINDOW win )
|
|
{
|
|
int cnt;
|
|
WindowInfo *info = window_list;
|
|
|
|
for ( cnt = 0; cnt < nbr_windows && info->win != win; cnt++, info++ )
|
|
;
|
|
if ( cnt == nbr_windows )
|
|
return NULL;
|
|
return info;
|
|
}
|
|
|
|
#if XIWS == XIWS_WIN || XIWS == XIWS_PM
|
|
static WindowInfo *
|
|
find_window_info_from_HWND( HWND win )
|
|
{
|
|
int cnt;
|
|
WindowInfo *info = window_list;
|
|
|
|
for ( cnt = 0; cnt < nbr_windows
|
|
&& ( HWND ) xvt_vobj_get_attr( info->win, ATTR_NATIVE_WINDOW ) != win;
|
|
cnt++, info++ )
|
|
;
|
|
if ( cnt == nbr_windows )
|
|
return NULL;
|
|
return info;
|
|
}
|
|
|
|
#endif
|
|
|
|
static void
|
|
deregister_window( WINDOW win )
|
|
{
|
|
WindowInfo *info;
|
|
|
|
info = find_window_info( win );
|
|
if ( info != NULL )
|
|
{
|
|
int cnt = ( int ) ( info - window_list );
|
|
|
|
--nbr_windows;
|
|
if ( nbr_windows > cnt )
|
|
memmove( window_list + cnt, window_list + cnt + 1,
|
|
( nbr_windows - cnt ) * sizeof( WindowInfo ) );
|
|
}
|
|
}
|
|
|
|
#if XIWS == XIWS_WM
|
|
static void
|
|
xi_fix_color( COLOR * color )
|
|
{
|
|
if ( *color == XI_COLOR_BLACK )
|
|
*color = XI_COLOR_WHITE;
|
|
else if ( *color == XI_COLOR_WHITE )
|
|
*color = XI_COLOR_BLACK;
|
|
}
|
|
|
|
#endif
|
|
|
|
#if XIWS == XIWS_PM
|
|
/* This function is required to fix a scrolling problem on PM. */
|
|
/**** RGM: This is a mess - there is only one "old_pm_proc" for all windows */
|
|
PFNWP old_pm_proc = NULL;
|
|
|
|
static MRESULT EXPENTRY
|
|
pm_proc( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 )
|
|
{
|
|
switch ( msg )
|
|
{
|
|
case WM_HSCROLL:
|
|
case WM_VSCROLL:
|
|
{
|
|
if ( SHORT2FROMMP( mp2 ) == SB_ENDSCROLL )
|
|
{
|
|
WinSetFocus( HWND_DESKTOP, hwnd );
|
|
return ( ( MRESULT ) 0 );
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
return ( old_pm_proc( hwnd, msg, mp1, mp2 ) );
|
|
}
|
|
|
|
#endif
|
|
|
|
/*START*/
|
|
/*
|
|
Abstractions:
|
|
|
|
Abstractions in this module encapsulate and contain state information for
|
|
certain entities that are necessary for the proper operation of this module.
|
|
The structures or classes that coorespond to these abstractions are defined
|
|
locally in this module. Code outside of this module only sees an opaque
|
|
data type, and *must* use functions in this module to manipulate the
|
|
abstractions. The developer of this module is free to put data members into
|
|
the locally defined structure or class, so that this module has the correct
|
|
state information to function properly.
|
|
|
|
XinWindow
|
|
|
|
this abstraction encapsulates the state and information for a created
|
|
window. also, we use an XinWindow to encapsulate the state and information
|
|
for horizontal and vertical scroll bars. scroll bars are the only controls
|
|
that Xin implements. XinWindow is also used for print windows.
|
|
|
|
examples are:
|
|
- the handle to the native window
|
|
- a pointer to the XinWindowEventHandler
|
|
- a pointer to the previous modal window, for proper implementation of modals
|
|
- a long integer for storing application data upon request of the module that
|
|
uses Xin
|
|
|
|
when creating an XinWindow, we pass in an XinWindowDef as an argument to
|
|
XinWindowCreate. an XinWindowDef contains all of the information necessary
|
|
to properly create either the scroll bar or the window. XinWindowType is an
|
|
enum that specifies whether to create a window or a scroll bar, and what kind
|
|
of window or scroll bar to create. The XinWindowMode determines "modality" of
|
|
the window. XinModeless is a normal window. XinModalReturn will create a window
|
|
that is the only window that can get focus and the XinWindowCreate function
|
|
will return as soon as the window is created. XinModalWait will create a window
|
|
that is the only window that can get focus and the XinWindowCreate function
|
|
will return when that window is destroyed. XinModalAutoclose will create a window
|
|
that will close automatically as soon as it loses focus. Note that XinModalReturn
|
|
and XinModalWait windows can be nested to open new modals windows. Creating
|
|
a modeless window while a modal window is open should create it without focus.
|
|
Autoclose windows can also be created "on top" of modal windows.
|
|
|
|
one of the more difficult things to handle is our concept of a modal window.
|
|
if MFC has a modal window, we should use it. however, if we need to implement
|
|
modal windows by disabling and re-enabling windows, we will wait until later
|
|
on in this project to implement them.
|
|
|
|
for historical reasons, in the XVT implementation, an XinWindow is, in fact,
|
|
the XVT window. this complicates the implementation because we then need to
|
|
keep state information on the window in a separate structure, and look up the
|
|
window information in a list whenever we need to access it. in the MFC
|
|
implementation, we will define a class that holds the state information on the
|
|
window, and the XinWindow should be a pointer to that class.
|
|
|
|
windows can be enabled or disabled. a disabled window still responds to
|
|
paint events, but can't be raised, and doesn't receive character or mouse
|
|
events.
|
|
|
|
windows can be visible or invisible. an invisible window does not generate
|
|
any paint events, nor receive character or mouse events.
|
|
|
|
Xin does not implement child windows.
|
|
|
|
the client area of a window is the area in which the module using Xin can draw.
|
|
the actual visible size of the window includes the border, title and menu which
|
|
are not part of the client area of the window. sometimes the
|
|
associated controls on the border are called the window decorations.
|
|
|
|
there are two XinWindows that are automatically created before
|
|
XinAppSystemSetupInit is called. the first is the task window. this allows
|
|
the module using Xin to manipulate the task window. the second is the screen
|
|
window. This allows Xin to draw directly onto the screen.
|
|
|
|
XinFont
|
|
|
|
this abstraction encapsulates the data necessary to specify a font. the
|
|
font can then be passed as an argument to XinWindowTextDraw, specifying
|
|
the font that the text is drawn in.
|
|
|
|
The XinFont can be created and set using a basic set of 'family' values, or
|
|
it can be the result of a font selection dialog. In either case, the
|
|
properties of 'bold', 'italic' and 'family' must be retrievable from the
|
|
XinFont. If the family does not match the basic set, then XinFontFamilyOther
|
|
will be used.
|
|
|
|
fonts can be mapped or unmapped.
|
|
after a font is mapped to a window, then the module using Xin can call
|
|
functions that use the font for drawing, or to get pixel metrics of the font.
|
|
if a font is mapped to a screen window, then the pixel metrics will be very
|
|
different than if the font is mapped to a printer window.
|
|
|
|
XinPrinterRec
|
|
|
|
This abstraction encapsulates the data for a selected printer.
|
|
It is used for printing operations and it should be possible to
|
|
save this structure in a file and load it later. (The size of
|
|
the structure is returned by XinPrintRecordCreate.)
|
|
|
|
XinBitmap
|
|
|
|
this abstraction encapsulates a bitmap that can be drawn into an XinWindow.
|
|
the internal format of an XinBitmap is the BMP format. this simplifies the
|
|
process of reading bitmaps from files or dlls, then subsequently drawing the
|
|
bitmap in a window.
|
|
|
|
XinRect
|
|
|
|
this structure contains the four points of a rectangle (top, left, bottom, right).
|
|
it is used in calls to many Xin functions.
|
|
|
|
XinPoint
|
|
|
|
this structure contains the horizontal and vertical components of a point (h, v)
|
|
|
|
Application
|
|
|
|
the Xin module contains the main (or win_main) or whatever function is
|
|
automatically executed when an MFC application starts. the module using Xin
|
|
needs to write two things for the minimal application. a function called
|
|
XinAppSystemSetupInit is written. this function initializes a data structure that
|
|
is passed in as an argument. this data structure defines certain application
|
|
wide characteristics such as the task window title, the task window event handler,
|
|
etc. in addition, the argc and argv variables are passed to this function for
|
|
processing if the user of Xin desires.
|
|
|
|
the sequence of actions when an application written using Xin starts is as follows:
|
|
1) win_main (or whatever in MFC) is called by the system.
|
|
2) win_main does any initial setup, puts argc and argv into the SystemSetup structure
|
|
3) win_main calls XinAppSystemSetupInit
|
|
4) data structures are set up so that when the system sends events to the MFC task
|
|
window handler, the events can be translated and sent to the Xin task window
|
|
event handler.
|
|
5) win_main returns.
|
|
6) windows starts sending event through to the task window event handler.
|
|
|
|
The "use_mdi" member of XinSystemSetup indicates if MDI should be enabled. The
|
|
Window menu will be specified with the tag XI_MENU_WIN. If that tag does not
|
|
exist, the Window menu will be created at the end of the existing menu.
|
|
The Window menu should contain Cascade, Tile Horizontally, Tile Vertically,
|
|
Close All, a separator(if any windows are open), and then the list of open windows,
|
|
including a "Windows..." item to open a separate dialog if there are too many
|
|
windows for the menu. Even if the XI_MENU_WIN tag exists, the window list will need
|
|
to be added to that existing menu. Of course, MDI will also handle iconizing of
|
|
top-level windows, etc.
|
|
|
|
Menus
|
|
|
|
Xin implements functions to manipulate menus. the functionality includes the
|
|
ability to set up an entire menu hierarchy with one call, replace a branch of
|
|
the menu hierarchy, replace a single item, change the enabled/disabled state of
|
|
any menu item, and change the checked state af a menu item.
|
|
|
|
there are no facilities to load menus from resources. the entire functionality
|
|
of the menu is available only through the api.
|
|
|
|
immediately after the application starts, the user of the Xin module will
|
|
call the function that sets up the entire menu. in the MFC implementation, we
|
|
may need to define a small "stub" menu in the windows resources. this stub
|
|
menu will not have anything in it other than a file menu with an exit item.
|
|
this stub menu will be replaced before the user has any oportunity to do any
|
|
menu selections.
|
|
|
|
there are two data structures associated with menus. an XinMenu is an array and
|
|
a count of child XinMenuItems an XinMenuItem is a branch on an XinMenu tree. it
|
|
may be the tip of a branch (a menu item that a user can select) or it may be the
|
|
parent of multiple child XinMenuItems, in which case, there is a submenu.
|
|
|
|
The text of menus can contain a '~' to indicate the shortcut key. For example,
|
|
"~File", "~Edit", and "E~xit".
|
|
|
|
Timers
|
|
|
|
this allows a module using Xin to set a timer
|
|
and get an event a specified number of miliseconds in the future. upon creation
|
|
of a timer, Xin returns a timer identifier (a long
|
|
integer) that identifies the timer. the timer id is part of the data for a timer
|
|
event, so that the module using Xin can set up multiple timers, and know which
|
|
timer an event is for. the timer identifier is also used when killing the timer.
|
|
|
|
Clipboard
|
|
|
|
Xin abstracts operations on the clipboard. the clipboard as implemented by Xin
|
|
can have two kinds of formats on it (text, and bitmap). any module using Xin can
|
|
query the clipboard, finding whether the desired format of data is on the clipboard,
|
|
then the module can get the contents of the clipboard.
|
|
|
|
Printing
|
|
|
|
printing has much in common with displayed windows. before printing, a print window
|
|
needs to be created. after the print window is created, fonts can be mapped to
|
|
the print window, rectangles, lines, and text can be drawn in the window, etc.
|
|
there is one fundimental difference. after the print window is created, the module
|
|
using Xin must call XinPrintPageStart. then, the module using Xin calls
|
|
XinPrintBandNext until it returns NULL. if it is necessary to paint a band at a
|
|
time, then XinPrintBandNext will return a rectangle several times. After each return,
|
|
the area within the returned rectangle should be drawn by the module using Xin. After
|
|
XinPrintBandNext returns NULL, then the module using Xin should call XinPrintPageEnd.
|
|
This will cause the page to be printed. If the printer and the printer driver are
|
|
capable of printing the entire page at once, then XinPrintBandNext will only return
|
|
a rectangle once.
|
|
|
|
Bob, according to a comment written by John Lilley in the report writer, banding is
|
|
no longer used for any XVT implementation. Do we really need to continue to support
|
|
banding?
|
|
|
|
If that's true, then no. But is it true? - Bob
|
|
|
|
*/
|
|
|
|
/*
|
|
Events
|
|
|
|
Xin is an event based system. When Xin is informed of certain events in the
|
|
underlying system, then Xin should send an event to the module using Xin. the
|
|
method of sending an event to the module using Xin is as follows:
|
|
|
|
1) declare an automatic variable of type XinEvent
|
|
2) set every byte in the XinEvent structure to '\0'
|
|
3) fill in the XinEvent structure. information that needs to be specified is
|
|
the event type, and information specific to that type of event.
|
|
4) call the event handler that the module using Xin specified when the application
|
|
was created, or when the window was created.
|
|
|
|
Below is the set of events that Xin needs to generate:
|
|
|
|
XinEventCreate
|
|
|
|
This event is sent when a window is created. When the application is starting,
|
|
then this event is sent to the task window event handler, which was specified
|
|
in the function XinAppSystemSetupInit. This will be the first event for any
|
|
window.
|
|
|
|
XinEventDestroy
|
|
|
|
This event is sent when a window is destroyed. When the application is
|
|
terminating, then this event is sent to the task window event handler. The
|
|
window will still be valid during this event, but no other event will occur
|
|
for the window after this event.
|
|
|
|
XinEventFocus
|
|
|
|
This event is sent when a window is gaining or loosing keyboard focus. A
|
|
boolean variable
|
|
in the XinEvent structure indicates whether the window is gaining or losing
|
|
focus.
|
|
|
|
XinEventResize
|
|
|
|
This event is sent when a window is re-sized or minimized.
|
|
|
|
XinEventPaint
|
|
|
|
This event is sent when the windowing system needs to have the module using
|
|
Xin paint a certain region of a window.
|
|
|
|
XinEventCloseButton
|
|
|
|
This event is sent when the user either clicks on the close button in the
|
|
upper right corner of the window, double clicks on the window menu at the
|
|
upper left corner of the window, or selects close on the window menu. the
|
|
window should not be closed when the above actions happen. rather, Xin
|
|
lets the module using Xin close the window if it desires.
|
|
|
|
XinEventMouseDown
|
|
|
|
This event is sent when the user presses the mouse button within the
|
|
bounderies of a window.
|
|
|
|
Xin reports the pressed state of the shift, control, and alt keys when
|
|
generating this event.
|
|
|
|
XinEventMouseUp
|
|
|
|
This event is sent when the user releases the mouse button within the
|
|
bounderies of a window. If the mouse is trapped to a window, then this
|
|
event is sent to the window in which the mouse is trapped, regardless of
|
|
whether the mouse is over that window or not.
|
|
|
|
Xin reports the pressed state of the shift, control, and alt keys when
|
|
generating this event.
|
|
|
|
XinEventMouseMove
|
|
|
|
This event is sent when the user moves the mouse within the bounderies
|
|
of a window. If the mouse is trapped to a window, then this
|
|
event is sent to the window in which the mouse is trapped, regardless of
|
|
whether the mouse is over that window or not. If the mouse is trapped to
|
|
a window, and the mouse is held down, then mouse move events are continually
|
|
generated, whether the mouse is moving or not.
|
|
|
|
Xin reports the pressed state of the shift, control, and alt keys when
|
|
generating this event.
|
|
|
|
XinEventMouseDouble
|
|
|
|
This event is sent when the user double clicks the mouse within the
|
|
bounderies of a window. The sequence of events when the user double clicks
|
|
and releases the mouse is:
|
|
XinEventMouseDown
|
|
XinEventMouseUp
|
|
XinEventMouseDouble
|
|
XinEventMouseUp
|
|
|
|
Xin reports the pressed state of the shift, control, and alt keys when
|
|
generating this event.
|
|
|
|
XinEventCharacter
|
|
|
|
This event is sent to a window when the window has keyboard focus, and the
|
|
user presses a key in the window. Character events are translated to
|
|
Xin virtual characters. The list of virtual characters is:
|
|
|
|
XI_KEY_DEL delete key
|
|
XI_KEY_UP up arrow key
|
|
XI_KEY_DOWN down arrow key
|
|
XI_KEY_RIGHT right arrow key
|
|
XI_KEY_LEFT left arrow key
|
|
XI_KEY_PREV page up key
|
|
XI_KEY_NEXT page down key
|
|
XI_KEY_LHOME home key
|
|
XI_KEY_LEND end key
|
|
XI_KEY_WLEFT control left arrow key
|
|
XI_KEY_WRIGHT control right arrow key
|
|
XI_KEY_BTAB shift tab key
|
|
XI_KEY_F1 function keys
|
|
XI_KEY_F2
|
|
XI_KEY_F3
|
|
XI_KEY_F4
|
|
XI_KEY_F5
|
|
XI_KEY_F6
|
|
XI_KEY_F7
|
|
XI_KEY_F8
|
|
XI_KEY_F9
|
|
XI_KEY_F10
|
|
XI_KEY_F11
|
|
XI_KEY_F12
|
|
|
|
Xin reports the pressed state of the shift, control, and alt keys when
|
|
generating this event.
|
|
|
|
XinEventMenuCommand
|
|
|
|
This event is sent when the user selects a menu item. The event reports the
|
|
menu tag of the selected menu item. There are no events for navigating menus.
|
|
|
|
Xin reports the pressed state of the shift and control keys when generating
|
|
this event.
|
|
|
|
XinEventControl
|
|
|
|
This event is sent when the user operates a scroll bar that was set up by
|
|
Xin. The control_id in the XinEvent structure is the control id specified
|
|
when the scroll bar was created.
|
|
|
|
In XinControlInformation, the following fields are set:
|
|
type is set to either XinWindowTypeHorizontalScrollBar or
|
|
XinWindowTypeVerticalScrollBar
|
|
win is set to the scroll bar window
|
|
v.scroll.action is set to one of XinScrollBarActionLineUp
|
|
XinScrollBarActionLineDown
|
|
XinScrollBarActionPageUp
|
|
XinScrollBarActionPageDown
|
|
XinScrollBarActionThumb
|
|
XinScrollBarActionThumbTrack
|
|
v.scroll.position is set to the current position of the thumb of the
|
|
scroll bar.
|
|
|
|
XinEventTimer
|
|
|
|
This event is sent when a timer expires. The module using Xin can set or
|
|
kill timers. See the discussion on timers for more details.
|
|
|
|
XinEventQuit
|
|
|
|
This event is sent when something or someone requests that Xin terminate.
|
|
For instance, when someone shuts down Windows95, then this event is sent.
|
|
The application, based on its state, can query the user to see if the user
|
|
wants to save changed data, discard changed data, or cancel the shutdown
|
|
operation. If, after processing input from the user, and it is still OK
|
|
to shut down, then the module using Xin should call XinAppQuitOk. If
|
|
XinAppQuitOk is not called, then the shutdown operation is aborted.
|
|
|
|
XinEventFont
|
|
|
|
This event does not need to be implemented in MFC.
|
|
|
|
*/
|
|
|
|
/*
|
|
Drawing
|
|
|
|
this section details the semantics and behaviors of drawing in windows.
|
|
|
|
Mathmatical Rectangles
|
|
|
|
Many of the Xin functions work using 'Mathmatical Rectangles'. By this, we
|
|
mean that a rectangle refers to the lines between the pixels, not the pixels
|
|
themselves. For instance, when we draw a rectangle, we specify a mathmatical
|
|
rectangle, and the pixels that get drawn are those just inside the mathmatical
|
|
rectangle.
|
|
|
|
the following diagram needs to be viewed in a fixed font to appear correctly.
|
|
it represents a grid of pixels where the mathmatical lines between the pixels
|
|
are numbered, and the spaces represent pixels.
|
|
|
|
0 1 2 3 4 5 6 7 8
|
|
0 -----------------
|
|
| | | | | | | | |
|
|
1 -----------------
|
|
| | | | | | | | |
|
|
2 -----------------
|
|
| | | | | | | | |
|
|
3 -----------------
|
|
| | | | | | | | |
|
|
4 -----------------
|
|
| | | | | | | | |
|
|
5 -----------------
|
|
| | | | | | | | |
|
|
6 -----------------
|
|
| | | | | | | | |
|
|
7 -----------------
|
|
| | | | | | | | |
|
|
-----------------
|
|
|
|
for instance, if we were to draw a hollow rectangle where:
|
|
top = 1
|
|
left = 1
|
|
right = 4
|
|
bottom = 4
|
|
then the following pixels would get drawn:
|
|
|
|
0 1 2 3 4 5 6 7 8
|
|
0 -----------------
|
|
| | | | | | | | |
|
|
1 -----------------
|
|
| |X|X|X| | | | |
|
|
2 -----------------
|
|
| |X| |X| | | | |
|
|
3 -----------------
|
|
| |X|X|X| | | | |
|
|
4 -----------------
|
|
| | | | | | | | |
|
|
5 -----------------
|
|
| | | | | | | | |
|
|
6 -----------------
|
|
| | | | | | | | |
|
|
7 -----------------
|
|
| | | | | | | | |
|
|
-----------------
|
|
|
|
at various points in this module, we will refer to mathmatical rectangles,
|
|
and to properly identify the semantics of drawing functions, we will
|
|
use diagrams like the ones above.
|
|
|
|
Clipping
|
|
|
|
when clipping is set for a window, the drawing functions only draw within
|
|
the clipping rectangle. the rectangle for clipping is a mathmatical
|
|
rectangle.
|
|
|
|
the functions that clip to the clipping rectangle are:
|
|
- XinWindowRectDraw
|
|
- XinWindowLineDraw
|
|
- XinWindowTextDraw
|
|
- XinWindowBitmapDraw
|
|
- XinWindowIconDraw
|
|
|
|
note that carets do not clip to the clipping rectangle. there is a
|
|
rectangle passed in to the XinWindowCaretOn for clipping of the caret.
|
|
|
|
Text Drawing
|
|
|
|
The vertical metrics of a font have three components: ascent, descent,
|
|
and leading. these are pixel counts of the components of a font.
|
|
|
|
____
|
|
leading ____
|
|
|
|
|
|
|
|
xxxxxx
|
|
x x
|
|
ascent x x
|
|
x x
|
|
baseline ____ xxxxx
|
|
x
|
|
descent x
|
|
____ xxxx
|
|
|
|
the baseline is the mathmatical line upon which most text (without
|
|
descenders) is drawn. ascent is the number of pixels above the
|
|
baseline to the top of the font. descent is the number of pixels
|
|
available for the descenders. leading is the space between the lines
|
|
of drawn text.
|
|
|
|
There are two modes of text drawing, opaque, and not opaque. If opaque,
|
|
the background color is drawn in the entire leading/ascent/descent area.
|
|
The background color is specified by XinWindowColorTextBackSet or by
|
|
the drawing tools.
|
|
|
|
If opaque is set to false, then only the text itself is drawn, using the
|
|
foreground color.
|
|
|
|
XinDrawMode
|
|
|
|
when drawing, there are two modes of drawing: copy and xor. if the draw
|
|
mode is copy, then the pixels are simply copied to the window. if the draw
|
|
mode is xor, then, if drawn on pixels equalling the back_color of the window,
|
|
drawing will attempt to produce the fore_color of the tool (pen/brush/text).
|
|
Drawing on pixels of fore_color will attempt to produce back_color. The
|
|
operation is self-reversing. the only thing that xor mode is used for is
|
|
drawing rubber band rectangles when moving columns, moving rows, resizing
|
|
columns and resizing rows. drawing in xor mode assumes that the window is
|
|
on top, and will remain on top until the rubber banding operation is complete.
|
|
|
|
XinPen
|
|
|
|
A pen specifies what is drawn for lines or rectangle borders. The 'width'
|
|
determines the number of pixels for the line or border. The 'pattern' may
|
|
be hollow, solid or dashed. If hollow, then no border will be drawn for a
|
|
rectangle. Solid and dashed lines are drawn using the 'fore_color'. Dashed
|
|
lines will not draw in the space between the dashes.
|
|
|
|
XinBrush
|
|
|
|
a brush specifies what is drawn in the interior of a rectangle. there are
|
|
two fields in an XinBrush data structure: 'pattern', and 'color'. if
|
|
'pattern' is XinBrushHollow, then 'color' is ignored, and the interior of
|
|
the rectangle (the pixels other than those just inside the mathmatical
|
|
rectangle) are left alone.
|
|
|
|
if 'pattern' is XinBrushSolid, then the pixels in the interior of the
|
|
rectangle are drawn in the specified color.
|
|
|
|
XinDrawTools
|
|
|
|
drawing tools is a convenience feature of Xin. it allows the user of Xin
|
|
to set or get the state of drawing (draw mode, brush, pen, fore color,
|
|
back color, and text opaqueness) with one function call.
|
|
|
|
Drawing Rectangles
|
|
|
|
There are three cases to consider when drawing rectangles:
|
|
|
|
1) solid pen and solid brush
|
|
2) hollow pen and solid brush
|
|
3) solid pen and hollow brush
|
|
|
|
note that it does not make any sense to draw with a hollow pen and a hollow
|
|
brush. this would draw nothing.
|
|
|
|
Example 1: solid red pen and solid blue brush
|
|
top = 1
|
|
left = 1
|
|
bottom = 5
|
|
right = 5
|
|
|
|
this will draw a red one pixel wide rectangle just inside the
|
|
specified mathmatical rectangle. it will fill the area inside
|
|
the red rectangle of pixels with blue pixels.
|
|
|
|
the following would be the result, r is a red pixel, b is a blue pixel
|
|
|
|
0 1 2 3 4 5 6 7 8
|
|
0 -----------------
|
|
| | | | | | | | |
|
|
1 -----------------
|
|
| |r|r|r|r| | | |
|
|
2 -----------------
|
|
| |r|b|b|r| | | |
|
|
3 -----------------
|
|
| |r|b|b|r| | | |
|
|
4 -----------------
|
|
| |r|r|r|r| | | |
|
|
5 -----------------
|
|
| | | | | | | | |
|
|
6 -----------------
|
|
| | | | | | | | |
|
|
7 -----------------
|
|
| | | | | | | | |
|
|
-----------------
|
|
|
|
Example 2: hollow pen and solid blue brush
|
|
top = 1
|
|
left = 1
|
|
bottom = 5
|
|
right = 5
|
|
|
|
this will fill the mathmatical rectangle with blue pixels.
|
|
|
|
the following would be the result, b is a blue pixel
|
|
|
|
0 1 2 3 4 5 6 7 8
|
|
0 -----------------
|
|
| | | | | | | | |
|
|
1 -----------------
|
|
| |b|b|b|b| | | |
|
|
2 -----------------
|
|
| |b|b|b|b| | | |
|
|
3 -----------------
|
|
| |b|b|b|b| | | |
|
|
4 -----------------
|
|
| |b|b|b|b| | | |
|
|
5 -----------------
|
|
| | | | | | | | |
|
|
6 -----------------
|
|
| | | | | | | | |
|
|
7 -----------------
|
|
| | | | | | | | |
|
|
-----------------
|
|
|
|
Example 3: solid blue pen and hollow brush
|
|
top = 1
|
|
left = 1
|
|
bottom = 5
|
|
right = 5
|
|
|
|
this will draw a blue rectangle, one pixel wide, just inside
|
|
the mathmatical rectangle.
|
|
|
|
the following would be the result, b is a blue pixel
|
|
|
|
0 1 2 3 4 5 6 7 8
|
|
0 -----------------
|
|
| | | | | | | | |
|
|
1 -----------------
|
|
| |b|b|b|b| | | |
|
|
2 -----------------
|
|
| |b| | |b| | | |
|
|
3 -----------------
|
|
| |b| | |b| | | |
|
|
4 -----------------
|
|
| |b|b|b|b| | | |
|
|
5 -----------------
|
|
| | | | | | | | |
|
|
6 -----------------
|
|
| | | | | | | | |
|
|
7 -----------------
|
|
| | | | | | | | |
|
|
-----------------
|
|
|
|
Drawing Lines
|
|
|
|
There are three cases to consider when drawing lines:
|
|
|
|
1) horizontal lines
|
|
2) vertical lines
|
|
3) diagonal lines
|
|
|
|
Example 1: a horizontal line
|
|
from
|
|
horizontal = 1
|
|
vertical = 1
|
|
to
|
|
horizontal = 6
|
|
vertical = 1
|
|
|
|
this will draw the row of pixels just below the mathmatical line.
|
|
|
|
0 1 2 3 4 5 6 7 8
|
|
0 -----------------
|
|
| | | | | | | | |
|
|
1 -----------------
|
|
| |x|x|x|x|x| | |
|
|
2 -----------------
|
|
| | | | | | | | |
|
|
3 -----------------
|
|
| | | | | | | | |
|
|
4 -----------------
|
|
| | | | | | | | |
|
|
5 -----------------
|
|
| | | | | | | | |
|
|
6 -----------------
|
|
| | | | | | | | |
|
|
7 -----------------
|
|
| | | | | | | | |
|
|
-----------------
|
|
|
|
Example 2: a vertical line
|
|
from
|
|
horizontal = 1
|
|
vertical = 1
|
|
to
|
|
horizontal = 1
|
|
vertical = 7
|
|
|
|
this will draw the row of pixels just to the right of
|
|
the mathmatical line.
|
|
|
|
0 1 2 3 4 5 6 7 8
|
|
0 -----------------
|
|
| | | | | | | | |
|
|
1 -----------------
|
|
| |x| | | | | | |
|
|
2 -----------------
|
|
| |x| | | | | | |
|
|
3 -----------------
|
|
| |x| | | | | | |
|
|
4 -----------------
|
|
| |x| | | | | | |
|
|
5 -----------------
|
|
| |x| | | | | | |
|
|
6 -----------------
|
|
| |x| | | | | | |
|
|
7 -----------------
|
|
| | | | | | | | |
|
|
-----------------
|
|
|
|
Example 3: a diagonal line
|
|
from
|
|
horizontal = 1
|
|
vertical = 1
|
|
to
|
|
horizontal = 4
|
|
vertical = 4
|
|
|
|
taking the mathmatical rectangle formed by placing the two points
|
|
at oposite corners, the two pixels just inside the corners of the
|
|
mathmatical rectangle are drawn, with some pixels in between. if
|
|
the absolute value of the rise and the run are equal, i.e. the line
|
|
is a diagonal line 45 degrees off of horizontal and vertical, then
|
|
a straight diagonal line is drawn.
|
|
|
|
|
|
0 1 2 3 4 5 6 7 8
|
|
0 -----------------
|
|
| | | | | | | | |
|
|
1 -----------------
|
|
| |x| | | | | | |
|
|
2 -----------------
|
|
| | |x| | | | | |
|
|
3 -----------------
|
|
| | | |x| | | | |
|
|
4 -----------------
|
|
| | | | | | | | |
|
|
5 -----------------
|
|
| | | | | | | | |
|
|
6 -----------------
|
|
| | | | | | | | |
|
|
7 -----------------
|
|
| | | | | | | | |
|
|
-----------------
|
|
|
|
Note: the adjustments that we need to make for MFC probably are the same as
|
|
the adjustments that are needed to be made for the Windows version of XVT.
|
|
|
|
|
|
*/
|
|
|
|
/*
|
|
Other Notes
|
|
|
|
Mouse Trapping
|
|
|
|
the mouse can be trapped to a window. when the mouse is trapped, all mouse
|
|
events until the mouse is released go to the window in which the mouse is
|
|
trapped. this ensures that if a window receives a mouse down event, it will
|
|
be guarenteed to receive the mouse up event.
|
|
|
|
while the mouse is trapped, if the mouse button is down, the window is
|
|
guarenteed to receive mouse move events even if the mouse is not moving. this
|
|
facilitates the behavior where the user is selecting text, drags the mouse
|
|
outside of the region where they are selecting text, and the text continually
|
|
scrolls until the user drags the mouse back into the region, or the user
|
|
releases the mouse button.
|
|
|
|
*/
|
|
|
|
/*
|
|
allocates memory on the heap. the size of the allocated block is indicated
|
|
by the argument 'size'. returns a pointer to the allocated memory.
|
|
*/
|
|
void *
|
|
XinMemoryAlloc( size_t size )
|
|
{
|
|
return malloc( size );
|
|
}
|
|
|
|
/*
|
|
frees memory previously allocated by XinMemoryAlloc. the pointer to the
|
|
memory is passed in as the argument 'ptr'.
|
|
*/
|
|
void
|
|
XinMemoryFree( void *ptr )
|
|
{
|
|
free( ptr );
|
|
}
|
|
|
|
/*
|
|
reallocates memory previously allocated by XinMemoryAlloc. the new size of
|
|
the allocated block is indicated by the argument 'size'. the pointer to be
|
|
reallocated is passed in as the argument 'ptr'. returns a pointer to the
|
|
allocated memory.
|
|
*/
|
|
void *
|
|
XinMemoryRealloc( void *ptr, size_t size )
|
|
{
|
|
return realloc( ptr, size );
|
|
}
|
|
|
|
/*
|
|
allocates and clears memory on the heap. the size of the allocated block
|
|
is indicated by the argument 'size'. returns a pointer to the allocated memory.
|
|
*/
|
|
void *
|
|
XinMemoryZeroAlloc( size_t size )
|
|
{
|
|
void *ptr = malloc( size );
|
|
|
|
memset( ptr, 0, size );
|
|
return ptr;
|
|
}
|
|
|
|
/*
|
|
puts up a modal dialog box with a message and up to three buttons. gets a
|
|
response from the user and returns XinResponse1 if button 1 is pressed.
|
|
returns XinResponse2 if button2 is pressed. returns XinResponse3 if button3
|
|
is pressed.
|
|
|
|
the argument 'Btn3' may be NULL, in which case only two buttons are put into
|
|
the dialog box.
|
|
|
|
the arguments 'Btn2' and 'Btn3' may be NULL, in which case only one button
|
|
is put into the dialog box.
|
|
|
|
the message is specified by a format and a variable number of arguments,
|
|
similar to the function printf
|
|
*/
|
|
XinResponse
|
|
XinDialogAsk( char *Btn1, char *Btn2, char *Btn3, char *format,... )
|
|
{
|
|
/*END*/
|
|
ASK_RESPONSE ask_response;
|
|
va_list argptr;
|
|
char button1[200], button2[200], button3[200];
|
|
|
|
XinInitBuffer( );
|
|
va_start( argptr, format );
|
|
vsprintf( xin_buffer, format, argptr );
|
|
va_end( argptr );
|
|
xin_buffer[200] = '\0';
|
|
if (Btn1 != NULL && strlen(Btn1) >= 200)
|
|
{
|
|
strncpy( button1, Btn1, 199 );
|
|
button1[199] = '\0';
|
|
Btn1 = button1;
|
|
}
|
|
if (Btn2 != NULL && strlen(Btn2) >= 200)
|
|
{
|
|
strncpy( button2, Btn2, 199 );
|
|
button2[199] = '\0';
|
|
Btn2 = button2;
|
|
}
|
|
if (Btn3 != NULL && strlen(Btn3) >= 200)
|
|
{
|
|
strncpy( button3, Btn3, 199 );
|
|
button3[199] = '\0';
|
|
Btn3 = button3;
|
|
}
|
|
ask_response = xvt_dm_post_ask( Btn1, Btn2, Btn3, xin_buffer );
|
|
switch ( ask_response )
|
|
{
|
|
case RESP_DEFAULT:
|
|
return XinResponse1;
|
|
case RESP_2:
|
|
return XinResponse2;
|
|
case RESP_3:
|
|
return XinResponse3;
|
|
}
|
|
return XinResponse1;
|
|
/*START*/
|
|
}
|
|
|
|
/*
|
|
puts up an error message modal dialog box.
|
|
|
|
the message is specified by a format and a variable number of arguments,
|
|
similar to the function printf
|
|
*/
|
|
void
|
|
XinDialogError( char *format,... )
|
|
{
|
|
/*END*/
|
|
va_list argptr;
|
|
|
|
XinInitBuffer( );
|
|
va_start( argptr, format );
|
|
vsprintf( xin_buffer, format, argptr );
|
|
va_end( argptr );
|
|
xin_buffer[200] = '\0';
|
|
xvt_dm_post_error( xin_buffer );
|
|
/*START*/
|
|
}
|
|
|
|
/*
|
|
puts up a fatal error message dialog box. this function should not return,
|
|
but should exit the application.
|
|
|
|
this function should not allocate any memory, as this function might have
|
|
been called because the heap is corrupted.
|
|
|
|
the message is specified by a format and a variable number of arguments,
|
|
similar to the function printf
|
|
*/
|
|
void
|
|
XinDialogFatal( char *format,... )
|
|
{
|
|
/*END*/
|
|
va_list argptr;
|
|
|
|
XinInitBuffer( );
|
|
va_start( argptr, format );
|
|
vsprintf( xin_buffer, format, argptr );
|
|
va_end( argptr );
|
|
xin_buffer[200] = '\0';
|
|
xvt_dm_post_fatal_exit( xin_buffer );
|
|
/*START*/
|
|
}
|
|
|
|
/*END*/
|
|
/* This is for a silly bug with openfile dialogs under windows. */
|
|
#if XIWS == XIWS_WIN
|
|
static void
|
|
open_file_hook( OPENFILENAME * lpofn )
|
|
{
|
|
lpofn->Flags |= OFN_PATHMUSTEXIST;
|
|
}
|
|
|
|
#endif
|
|
|
|
/*START*/
|
|
/*
|
|
this function puts up a file open or a file save modal dialog box.
|
|
|
|
the string in the argument 'message' is put into the dialog box as a prompt
|
|
for the user.
|
|
|
|
if the argument 'type' is XinOpenFileDialog then the open file dialog box is
|
|
put up. this allows the user to specify a name of a file to be opened for
|
|
reading. the user is supplied with a list of files to choose from. the
|
|
user also may change directories to search for the desired file. if a valid
|
|
filename is specifed by the user, then this function returns XinFileGood. if an
|
|
error occurs, then this function returns XinFileBad after an appropriate error
|
|
message is displayed.
|
|
if the user canceled the dialog box without specifying a file name, then this
|
|
function returns XinFileCancel. upon entry to the function, the argument 'spec'
|
|
specifies the file type (a three character extension for the MFC implementation),
|
|
the starting directory and the starting file name if desired. see the definition
|
|
of XinFileSpec for further details. when this function returns, if XinFileGood
|
|
is the returned status, then the argument 'spec' is filled in with the specified
|
|
file and directory.
|
|
|
|
if the argument type is XinSaveFileDialog then the save file dialog box is
|
|
put up. this allows the user to specify a name of a file to be created, or
|
|
opened for writing. the user is supplied with a list of files to choose from. the
|
|
user also may change directories to search for the desired file. if a valid
|
|
filename is specifed by the user, then this function returns XinFileGood. if an
|
|
error occurs, then this function returns XinFileBad after an appropriate message
|
|
is displayed.
|
|
if the user canceled the dialog box without specifying a file name, then this
|
|
function returns XinFileCancel. upon entry to the function, the argument 'spec'
|
|
specifies the file type (a three character extension for the MFC implementation),
|
|
the starting directory and the starting file name if desired. see the definition
|
|
of XinFileSpec for further details. when this function returns, if XinFileGood
|
|
is the returned status, then the argument 'spec' is filled in with the specified
|
|
file and directory.
|
|
|
|
the implementation for MFC should simply put up the standard open or save file
|
|
dialog.
|
|
*/
|
|
XinFileResult
|
|
XinDialogFile( char *message, XinFileSpec * spec, XinFileDialogType type )
|
|
{
|
|
/*END*/
|
|
FL_STATUS result;
|
|
FILE_SPEC xvt_spec;
|
|
|
|
#if XIWS == XIWS_WIN
|
|
long old_hook;
|
|
|
|
#endif
|
|
|
|
#if XIWS == XIWS_MAC
|
|
strncpy( xvt_spec.type, spec->type, sizeof( xvt_spec.type ) - 1 );
|
|
strncpy( xvt_spec.name, spec->file_name, SZ_FNAME );
|
|
xvt_spec.name[SZ_FNAME] = '\0';
|
|
#else
|
|
if ( type == XinOpenFileDialog )
|
|
{
|
|
char *dot_ptr = strchr( spec->file_name, '.' );
|
|
|
|
if ( dot_ptr != NULL )
|
|
strcpy( xvt_spec.type, dot_ptr + 1 );
|
|
else {
|
|
if (spec->type != NULL)
|
|
strcpy( xvt_spec.type, spec->type );
|
|
else
|
|
xvt_spec.type[0] = '\0';
|
|
}
|
|
}
|
|
else
|
|
{
|
|
strncpy( xvt_spec.type, spec->type, sizeof( xvt_spec.type ) - 1 );
|
|
strncpy( xvt_spec.name, spec->file_name, SZ_FNAME );
|
|
xvt_spec.name[SZ_FNAME] = '\0';
|
|
}
|
|
#endif
|
|
xvt_fsys_convert_str_to_dir( ( char * ) spec->directory, &xvt_spec.dir );
|
|
#if XIWS == XIWS_WIN
|
|
old_hook = xvt_vobj_get_attr( NULL_WIN, ATTR_WIN_OPENFILENAME_HOOK );
|
|
xvt_vobj_set_attr( NULL_WIN, ATTR_WIN_OPENFILENAME_HOOK,
|
|
( long ) open_file_hook );
|
|
#endif
|
|
if ( type == XinOpenFileDialog )
|
|
result = xvt_dm_post_file_open( &xvt_spec, message );
|
|
else
|
|
result = xvt_dm_post_file_save( &xvt_spec, message );
|
|
#if XIWS == XIWS_WIN
|
|
xvt_vobj_set_attr( NULL_WIN, ATTR_WIN_OPENFILENAME_HOOK, old_hook );
|
|
#endif
|
|
switch ( result )
|
|
{
|
|
case FL_OK:
|
|
xvt_fsys_convert_dir_to_str( &xvt_spec.dir, ( char * ) spec->directory,
|
|
sizeof( XinDirectory ) );
|
|
strncpy( spec->file_name, xvt_spec.name, XI_FILE_MAX );
|
|
spec->file_name[XI_FILE_MAX] = '\0';
|
|
return XinFileGood;
|
|
case FL_CANCEL:
|
|
return XinFileCancel;
|
|
case FL_BAD:
|
|
return XinFileBad;
|
|
}
|
|
return XinFileBad;
|
|
/*START*/
|
|
}
|
|
|
|
/*
|
|
this function puts up the standard font selection dialog box. upon selection of
|
|
a font by the user, the argument 'font' is set to the specified font.
|
|
|
|
if the user canceled, then this function returns FALSE. if the user specified
|
|
a font, then this function returns TRUE.
|
|
*/
|
|
BOOLEAN
|
|
XinDialogFont( XinFont * font )
|
|
{
|
|
/*END*/
|
|
if ( !xvt_dm_post_font_sel( NULL_WIN, font->xvt_fntid, NULL, 0L ) )
|
|
return FALSE;
|
|
font->from_xvt_font = TRUE;
|
|
XinFontNativeConvert( font );
|
|
return TRUE;
|
|
/*START*/
|
|
}
|
|
|
|
/*
|
|
puts up a modal dialog box that displays a note with a single "OK" button.
|
|
|
|
the message is specified by a format and a variable number of arguments,
|
|
similar to the function printf
|
|
*/
|
|
void
|
|
XinDialogNote( char *format,... )
|
|
{
|
|
/*END*/
|
|
va_list argptr;
|
|
|
|
XinInitBuffer( );
|
|
va_start( argptr, format );
|
|
vsprintf( xin_buffer, format, argptr );
|
|
va_end( argptr );
|
|
xin_buffer[200] = '\0';
|
|
xvt_dm_post_note( xin_buffer );
|
|
/*START*/
|
|
}
|
|
|
|
/*
|
|
this function puts up a printer setup dialog box. this allows the user to
|
|
select a printer and setup options for that printer.
|
|
|
|
this function should put up the standard printer setup dialog box in MFC.
|
|
|
|
this function fills in an XinPrintRecord, which is an abstraction implemented
|
|
locally in this module. see the abstraction discussion on XinPrintRecord above.
|
|
*/
|
|
BOOLEAN
|
|
XinDialogPrinterSetup( XinPrintRecord * rec )
|
|
{
|
|
/*END*/
|
|
return xvt_dm_post_page_setup( ( PRINT_RCD * ) rec );
|
|
/*START*/
|
|
}
|
|
|
|
/*
|
|
this function puts up a dialog box with a message, and gets a string response
|
|
from the user. the argument 'message' contains the prompt for the user.
|
|
the argument 'response' points to a character buffer, which is filled in
|
|
with the user's response. the argument 'response_len' contains the length
|
|
of the character array pointed to by 'response'. this function should never
|
|
copy more characters into 'response' than 'response_len' to avoid overwriting
|
|
memory and corrupting the heap.
|
|
|
|
this function returns the value in 'response' if the user typed a string and
|
|
pressed OK. if the user pressed cancel, then this function returns NULL.
|
|
*/
|
|
char *
|
|
XinDialogStringPrompt( char *message, char *response, int response_len )
|
|
{
|
|
/*END*/
|
|
return xvt_dm_post_string_prompt( message, response, response_len );
|
|
/*START*/
|
|
}
|
|
|
|
/*
|
|
each XinWindow can have an arbitrary long integer associated with it for
|
|
storing of state data with the window. typically, the module that uses
|
|
Xin will allocate memory for data, fill in the data structure, and pass
|
|
the allocated pointer to XinWindowAppDataSet, casting the pointer to a
|
|
long in the call.
|
|
|
|
this function simply sets the app data field in the XinWindow abstraction
|
|
to the argument 'AppData'.
|
|
*/
|
|
void
|
|
XinWindowAppDataSet( XinWindow Win, long AppData )
|
|
{
|
|
/*END*/
|
|
xvt_vobj_set_data( ( WINDOW ) Win, AppData );
|
|
/*START*/
|
|
}
|
|
|
|
/*
|
|
this function returns a value previously passed to XinWindowAppDataSet for
|
|
the specified window.
|
|
*/
|
|
long
|
|
XinWindowAppDataGet( XinWindow Win )
|
|
{
|
|
/*END*/
|
|
return xvt_vobj_get_data( ( WINDOW ) Win );
|
|
/*START*/
|
|
}
|
|
|
|
void
|
|
XinWindowArcDraw( XinWindow Win, XinRect* rctp, XinPoint* start, XinPoint* stop )
|
|
{
|
|
RCT r;
|
|
|
|
r.left = rctp->left;
|
|
r.top = rctp->top;
|
|
r.right = rctp->right;
|
|
r.bottom = rctp->bottom;
|
|
xvt_dwin_draw_arc( (WINDOW) Win, &r, start->h, start->v, stop->h, stop->v );
|
|
}
|
|
|
|
/*
|
|
this function draws the bitmap specified in the argument 'bitmap' into the
|
|
window specified by 'win'.
|
|
|
|
'source' specifies a mathmatical rectangle which may be a subsection of the
|
|
specified bitmap. if 'source' is the same size as the bitmap, then the entire
|
|
bitmap is drawn.
|
|
|
|
'dest' specifies the destination rectangle in the window.
|
|
|
|
if 'source' and 'dest' are not the same size, then this function scales the
|
|
bitmap to fit.
|
|
*/
|
|
void
|
|
XinWindowBitmapDraw( XinWindow win, XinBitmap * bitmap, XinRect * dest, XinRect * source )
|
|
{
|
|
/*END*/
|
|
xvt_dwin_draw_image( ( WINDOW ) win, bitmap->image, ( RCT * ) dest, ( RCT * ) source );
|
|
/*START*/
|
|
}
|
|
|
|
/*END*/
|
|
static PAT_STYLE
|
|
BrushPatternToPAT( XinBrushPattern Pattern )
|
|
{
|
|
switch ( Pattern )
|
|
{
|
|
case XinBrushSolid:
|
|
return PAT_SOLID;
|
|
case XinBrushHollow:
|
|
return PAT_HOLLOW;
|
|
default:
|
|
break;
|
|
}
|
|
return PAT_SOLID;
|
|
}
|
|
|
|
static PAT_STYLE
|
|
PenPatternToPAT( XinPenPattern Pattern )
|
|
{
|
|
switch ( Pattern )
|
|
{
|
|
case XinPenSolid:
|
|
return PAT_SOLID;
|
|
case XinPenHollow:
|
|
return PAT_HOLLOW;
|
|
case XinPenDashed:
|
|
return PAT_RUBBER;
|
|
default:
|
|
break;
|
|
}
|
|
return PAT_SOLID;
|
|
}
|
|
|
|
static XinBrushPattern
|
|
PATToBrushPattern( PAT_STYLE pat )
|
|
{
|
|
switch ( pat )
|
|
{
|
|
case PAT_SOLID:
|
|
return XinBrushSolid;
|
|
case PAT_HOLLOW:
|
|
return XinBrushHollow;
|
|
default:
|
|
break;
|
|
}
|
|
return XinBrushSolid;
|
|
}
|
|
|
|
static XinPenPattern
|
|
PATToPenPattern( PAT_STYLE pat )
|
|
{
|
|
switch ( pat )
|
|
{
|
|
case PAT_SOLID:
|
|
return XinPenSolid;
|
|
case PAT_HOLLOW:
|
|
return XinPenHollow;
|
|
case PAT_RUBBER:
|
|
return XinPenDashed;
|
|
default:
|
|
break;
|
|
}
|
|
return XinPenSolid;
|
|
}
|
|
|
|
/*START*/
|
|
|
|
/*
|
|
this function sets the brush for subsequent rectangle drawing operations.
|
|
|
|
see the drawing discussion above for details on drawing.
|
|
*/
|
|
void
|
|
XinWindowBrushSet( XinWindow win, XinBrush * brush )
|
|
{
|
|
/*END*/
|
|
CBRUSH cbrush;
|
|
|
|
#ifdef NEED_PATCH
|
|
/* Hack for OS2 */
|
|
/* The calls to XinWindowDrawToolsNormalGet and DrawToolsSet
|
|
cause a update problem in the link list edit window */
|
|
#if XIWS == XIWS_PM
|
|
if ( brush->fore_color == XI_COLOR_LTGRAY )
|
|
{
|
|
XinBrush hollow_cbrush;
|
|
XinRect rct;
|
|
|
|
/* Bad bug with XVT/PM, needs this before can draw COLOR_LTGRAY */
|
|
XinWindowDrawToolsNormalGet( &t );
|
|
win_set_draw_ctools( win, &t );
|
|
hollow_cbrush.color = XI_COLOR_WHITE;
|
|
hollow_cbrush.pat = XinPatternHollow;
|
|
win_set_cbrush( win, &hollow_cbrush );
|
|
rct.top = 0;
|
|
rct.left = 0;
|
|
rct.bottom = 0;
|
|
rct.right = 0;
|
|
xi_draw_rect( win, &rct );
|
|
}
|
|
#endif
|
|
#if XIWS == XIWS_XM || XIWS == XIWS_WXGTK
|
|
if ( brush->fore_color == XI_COLOR_LTGRAY )
|
|
{
|
|
/* X GRAY SCALE HACK */
|
|
XinWindowBackColorSet( win, XI_COLOR_WHITE );
|
|
{
|
|
XinDrawTools ct;
|
|
|
|
XinWindowDrawToolsGet( win, &ct );
|
|
ct.opaque_text = FALSE;
|
|
XinWindowDrawToolsSet( win, &ct );
|
|
xi_draw_text( win, 0, 0, " ", -1 );
|
|
}
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
cbrush.color = brush->fore_color;
|
|
cbrush.pat = BrushPatternToPAT( brush->pattern );
|
|
#if XIWS == XIWS_WM
|
|
xi_fix_color( &cbrush.color );
|
|
#endif
|
|
xvt_dwin_set_cbrush( ( WINDOW ) win, &cbrush );
|
|
/*START*/
|
|
}
|
|
|
|
/*END*/
|
|
static BOOLEAN caret_is_on = FALSE;
|
|
|
|
/*START*/
|
|
/*
|
|
the caret is the blinking vertical line that indicates the current insertion
|
|
point when editing text.
|
|
|
|
this function turns off the caret in the specified window.
|
|
*/
|
|
void
|
|
XinWindowCaretOff( XinWindow win )
|
|
{
|
|
/*END*/
|
|
#if XIWS == XIWS_WIN
|
|
PNT p;
|
|
|
|
if ( !caret_is_on )
|
|
return;
|
|
p.h = -100;
|
|
p.v = -100;
|
|
xvt_win_set_caret_pos( ( WINDOW ) win, p );
|
|
#endif
|
|
caret_is_on = FALSE;
|
|
xvt_win_set_caret_visible( ( WINDOW ) win, FALSE );
|
|
/*START*/
|
|
}
|
|
|
|
/*
|
|
this function turns on a caret in the specified window 'win'
|
|
|
|
'x' and 'y' specify the position of the bottom of the caret.
|
|
|
|
'height' specifies the height of the caret.
|
|
|
|
'assumed_back_color' is not used for the MFC implementation.
|
|
|
|
'clip_rct' specifies a clipping rectangle for the caret. If the caret is
|
|
totally outside of the clipping rectangle, then the caret is not turned on.
|
|
if the caret is completely inside of the clipping rectangle, then the caret
|
|
is turned on normally. if the caret is partially outside of the clipping
|
|
rectangle, then the actual height is reduced, and position of the caret is
|
|
modified so that it appears as if the caret is clipped by the clipping rectangle.
|
|
*/
|
|
void
|
|
XinWindowCaretOn( XinWindow win, int x, int y, int height, XinColor assumed_back_color,
|
|
XinRect * clip_rct )
|
|
{
|
|
/*END*/
|
|
PNT p;
|
|
int dist_from_top;
|
|
|
|
NOREF( assumed_back_color );
|
|
if ( caret_is_on )
|
|
return;
|
|
caret_is_on = TRUE;
|
|
|
|
p.h = x;
|
|
p.v = y;
|
|
|
|
/* If the caret base is outsde the bottom of the clip rectangle - set the
|
|
* caret base to the clip bottom and adjust the caret height */
|
|
|
|
if ( clip_rct )
|
|
{
|
|
if ( p.v > clip_rct->bottom )
|
|
{
|
|
int adjust = p.v - clip_rct->bottom;
|
|
|
|
height = height - adjust;
|
|
|
|
p.v = clip_rct->bottom;
|
|
}
|
|
|
|
/* If the caret height is taller than the clip rectangle adjust it */
|
|
|
|
dist_from_top = p.v - clip_rct->top;
|
|
|
|
if ( height > dist_from_top )
|
|
height = dist_from_top;
|
|
}
|
|
|
|
/* The calculations above could result in a height of 0 or less if that is
|
|
* the case there is no caret */
|
|
if ( height > 0 )
|
|
{
|
|
#if 0
|
|
{ /* This patches a bug in the caret position in
|
|
* XVT/WIN */
|
|
int leading,
|
|
ascent,
|
|
descent;
|
|
|
|
xvt_dwin_get_font_metrics( ( WINDOW ) win, &leading, &ascent, &descent );
|
|
p.v -= height - ( leading + ascent + descent );
|
|
}
|
|
#endif
|
|
xvt_win_set_caret_size( ( WINDOW ) win, XIN_CARET_WIDTH, height );
|
|
xvt_win_set_caret_pos( ( WINDOW ) win, p );
|
|
xvt_win_set_caret_visible( ( WINDOW ) win, TRUE );
|
|
}
|
|
/*START*/
|
|
}
|
|
|
|
/*END*/
|
|
/*
|
|
non-xvt versions do not need to support this function
|
|
*/
|
|
void
|
|
XinWindowCheckBox( XinWindow Win, BOOLEAN Check )
|
|
{
|
|
/*
|
|
#if XIWS != XIWS_XM
|
|
*/
|
|
xvt_ctl_set_checked( ( WINDOW ) Win, Check );
|
|
/*
|
|
#endif
|
|
*/
|
|
}
|
|
|
|
/*
|
|
non-xvt versions do not need to support this function
|
|
*/
|
|
void
|
|
XinWindowCheckRadioButton( XinWindow Win, XinWindow * Wins, int NbrWindows )
|
|
{
|
|
xvt_ctl_check_radio_button( ( WINDOW ) Win, ( WINDOW * ) Wins, NbrWindows );
|
|
}
|
|
|
|
/*START*/
|
|
/*
|
|
this function gets the current clipping rectangle for the specified window.
|
|
|
|
the caller of this function passes in a pointer to a rectangle for the argument
|
|
'rctp'. this rectangle is filled in with the clipping region.
|
|
|
|
this function always returns TRUE.
|
|
|
|
see the discussion on drawing for further details.
|
|
*/
|
|
BOOLEAN
|
|
XinWindowClipGet( XinWindow win, XinRect * rctp )
|
|
{
|
|
/*END*/
|
|
( XinRect * ) xvt_dwin_get_clip( ( WINDOW ) win, ( RCT * ) rctp );
|
|
/*** TODO: if rctp is very large, return FALSE ***/
|
|
return TRUE;
|
|
/*START*/
|
|
}
|
|
|
|
/*
|
|
this function sets the clipping rectangle for the specified window.
|
|
|
|
'rctp' points to the desired mathmatical clipping rectangle.
|
|
*/
|
|
void
|
|
XinWindowClipSet( XinWindow win, XinRect * rctp )
|
|
{
|
|
/*END*/
|
|
xvt_dwin_set_clip( ( WINDOW ) win, ( RCT * ) rctp );
|
|
/*START*/
|
|
}
|
|
|
|
/*
|
|
this function sets the background color to use when drawing text in
|
|
opaque mode.
|
|
|
|
see the drawing discussion above for additional details on opaque drawing
|
|
of text.
|
|
*/
|
|
void
|
|
XinWindowColorTextBackSet( XinWindow win, XinColor color )
|
|
{
|
|
/*END*/
|
|
#if XIWS == XIWS_WM
|
|
xi_fix_color( &color );
|
|
#endif
|
|
xvt_dwin_set_back_color( ( WINDOW ) win, color );
|
|
/*START*/
|
|
}
|
|
|
|
/*
|
|
this function sets the foreground color to use when drawing text in
|
|
both opaque and non-opaque mode.
|
|
|
|
see the drawing discussion above for details on drawing text.
|
|
*/
|
|
void
|
|
XinWindowColorTextForeSet( XinWindow win, XinColor color )
|
|
{
|
|
/*END*/
|
|
xvt_dwin_set_fore_color( ( WINDOW ) win, color );
|
|
/*START*/
|
|
}
|
|
|
|
/*END*/
|
|
static XinScrollBarAction
|
|
ConvertWhat( SCROLL_CONTROL scroll_control )
|
|
{
|
|
switch ( scroll_control )
|
|
{
|
|
case SC_LINE_UP:
|
|
return XinScrollBarActionLineUp;
|
|
case SC_LINE_DOWN:
|
|
return XinScrollBarActionLineDown;
|
|
case SC_PAGE_UP:
|
|
return XinScrollBarActionPageUp;
|
|
case SC_PAGE_DOWN:
|
|
return XinScrollBarActionPageDown;
|
|
case SC_THUMB:
|
|
return XinScrollBarActionThumb;
|
|
case SC_THUMBTRACK:
|
|
return XinScrollBarActionThumbTrack;
|
|
default:
|
|
break;
|
|
}
|
|
return XinScrollBarActionLineUp;
|
|
}
|
|
|
|
XinFont *
|
|
XinFontXvtConvert( void *font_id )
|
|
{
|
|
XinFont *font = XinMemoryZeroAlloc( sizeof( XinFont ) );
|
|
|
|
font->xvt_fntid = xvt_font_create( );
|
|
xvt_font_copy( font->xvt_fntid, ( XVT_FNTID ) font_id,
|
|
( unsigned long ) XVT_FA_ALL );
|
|
font->from_xvt_font = TRUE;
|
|
return font;
|
|
}
|
|
|
|
void *
|
|
XinFontXvtConvertBack( XinFont * font )
|
|
{
|
|
return font->xvt_fntid;
|
|
}
|
|
|
|
void
|
|
XinFontXvtDestroy( void *font_id )
|
|
{
|
|
xvt_font_destroy( ( XVT_FNTID ) font_id );
|
|
}
|
|
|
|
#define FONT_ATTR_SIZE 256 /* family or native_desc size */
|
|
|
|
/*
|
|
This function fills out a font based on its native fontid, perhaps one from a font dialog.
|
|
Afterwards, the font is guaranteed to respond correctly to family, size, bold, and italic
|
|
inquiries, except that family may be XinFontFamilyOther.
|
|
*/
|
|
static int xin_stricmp( const char* s1, const char* s2 )
|
|
{
|
|
while (*s1 && *s2 && toupper(*s1) == toupper(*s2))
|
|
{
|
|
s1++;
|
|
s2++;
|
|
}
|
|
return toupper(*s2) - toupper(*s1);
|
|
}
|
|
|
|
static char *xin_family_name_times = NULL;
|
|
static char *xin_family_name_fixed = NULL;
|
|
static char *xin_family_name_helvetica = NULL;
|
|
static char *xin_family_name_system = NULL;
|
|
static BOOLEAN xin_family_names_initialized = FALSE;
|
|
|
|
void
|
|
XinFontNativeConvert( XinFont * font )
|
|
{
|
|
if (font->from_xvt_font)
|
|
{
|
|
char buf1[FONT_ATTR_SIZE];
|
|
XinFontFamily family;
|
|
unsigned long attrib;
|
|
|
|
if (!xin_family_names_initialized)
|
|
{ /* We need to know what XVT is really mapping the fonts to. */
|
|
char buf[100];
|
|
XVT_FNTID font_id = xvt_font_create();
|
|
WINDOW font_win;
|
|
XinWindowDef Def;
|
|
XinRect rect = {-1000, -1000, -900, -900};
|
|
|
|
MEMCLEAR( Def );
|
|
Def.type = XinWindowTypeDocument;
|
|
Def.border_style = XinBorderFixed;
|
|
Def.p_rect = ▭
|
|
Def.title = "";
|
|
font_win = (WINDOW)XinWindowCreate( &Def );
|
|
xvt_font_map( font_id, font_win );
|
|
if (xvt_font_get_family_mapped( font_id, buf, 99 ))
|
|
{
|
|
xin_family_name_system = (char*)XinMemoryAlloc( strlen( buf ) + 1 );
|
|
strcpy( xin_family_name_system, buf );
|
|
}
|
|
xvt_font_set_family( font_id, "times" );
|
|
xvt_font_map( font_id, font_win );
|
|
if (xvt_font_get_family_mapped( font_id, buf, 99 ))
|
|
{
|
|
xin_family_name_times = (char*)XinMemoryAlloc( strlen( buf ) + 1 );
|
|
strcpy( xin_family_name_times, buf );
|
|
}
|
|
xvt_font_set_family( font_id, "fixed" );
|
|
xvt_font_map( font_id, font_win );
|
|
if (xvt_font_get_family_mapped( font_id, buf, 99 ))
|
|
{
|
|
xin_family_name_fixed = (char*)XinMemoryAlloc( strlen( buf ) + 1 );
|
|
strcpy( xin_family_name_fixed, buf );
|
|
}
|
|
xvt_font_set_family( font_id, "helvetica" );
|
|
xvt_font_map( font_id, font_win );
|
|
if (xvt_font_get_family_mapped( font_id, buf, 99 ))
|
|
{
|
|
xin_family_name_helvetica = (char*)XinMemoryAlloc( strlen( buf ) + 1 );
|
|
strcpy( xin_family_name_helvetica, buf );
|
|
}
|
|
xvt_font_destroy( font_id );
|
|
XinWindowDestroy( (XinWindow)font_win );
|
|
xin_family_names_initialized = TRUE;
|
|
}
|
|
|
|
if ( !xvt_font_get_family( font->xvt_fntid, buf1, FONT_ATTR_SIZE ) )
|
|
return;
|
|
|
|
if (xin_stricmp( buf1, xin_family_name_system ) == 0)
|
|
family = XinFontFamilySystem;
|
|
else if (xin_stricmp( buf1, xin_family_name_fixed ) == 0)
|
|
family = XinFontFamilyFixed;
|
|
else if (xin_stricmp( buf1, xin_family_name_times ) == 0)
|
|
family = XinFontFamilyTimes;
|
|
else if (xin_stricmp( buf1, xin_family_name_helvetica) == 0)
|
|
family = XinFontFamilyHelvetica;
|
|
else
|
|
family = XinFontFamilyOther;
|
|
font->family = family;
|
|
attrib = xvt_font_get_style( font->xvt_fntid );
|
|
font->italic = (attrib & XVT_FS_ITALIC ? TRUE : FALSE);
|
|
font->bold = (attrib & XVT_FS_BOLD ? TRUE : FALSE);
|
|
font->size = (int)xvt_font_get_size( font->xvt_fntid );
|
|
font->from_xvt_font = FALSE;
|
|
}
|
|
}
|
|
|
|
static BOOLEAN
|
|
ConvertEvent( EVENT * ep, XinEvent * xiep )
|
|
{
|
|
BOOLEAN retval = TRUE;
|
|
|
|
switch ( ep->type )
|
|
{
|
|
case E_CREATE:
|
|
xiep->type = XinEventCreate;
|
|
break;
|
|
case E_DESTROY:
|
|
xiep->type = XinEventDestroy;
|
|
break;
|
|
case E_FOCUS:
|
|
xiep->type = XinEventFocus;
|
|
xiep->v.focus.active = ep->v.active;
|
|
break;
|
|
case E_SIZE:
|
|
xiep->type = XinEventResize;
|
|
xiep->v.resize.width = ep->v.size.width;
|
|
xiep->v.resize.height = ep->v.size.height;
|
|
break;
|
|
case E_UPDATE:
|
|
xiep->type = XinEventPaint;
|
|
xiep->v.paint.rect = *( XinRect * ) & ep->v.update.rct;
|
|
break;
|
|
case E_CLOSE:
|
|
xiep->type = XinEventCloseButton;
|
|
break;
|
|
case E_MOUSE_DOWN:
|
|
xiep->type = XinEventMouseDown;
|
|
xiep->v.mouse.where.v = ep->v.mouse.where.v;
|
|
xiep->v.mouse.where.h = ep->v.mouse.where.h;
|
|
xiep->v.mouse.shift = ep->v.mouse.shift;
|
|
xiep->v.mouse.control = ep->v.mouse.control;
|
|
xiep->v.mouse.button = ep->v.mouse.button;
|
|
break;
|
|
case E_MOUSE_UP:
|
|
xiep->type = XinEventMouseUp;
|
|
xiep->v.mouse.where.v = ep->v.mouse.where.v;
|
|
xiep->v.mouse.where.h = ep->v.mouse.where.h;
|
|
xiep->v.mouse.shift = ep->v.mouse.shift;
|
|
xiep->v.mouse.control = ep->v.mouse.control;
|
|
xiep->v.mouse.button = ep->v.mouse.button;
|
|
#ifndef NO_PRIMARY_SELECTION
|
|
#if XIWS == XIWS_XM
|
|
if ( xiep->v.mouse.button == 2 )
|
|
get_primary_selection( itf, win );
|
|
#endif
|
|
#endif
|
|
break;
|
|
case E_MOUSE_MOVE:
|
|
xiep->type = XinEventMouseMove;
|
|
xiep->v.mouse.where.v = ep->v.mouse.where.v;
|
|
xiep->v.mouse.where.h = ep->v.mouse.where.h;
|
|
xiep->v.mouse.shift = ep->v.mouse.shift;
|
|
xiep->v.mouse.control = ep->v.mouse.control;
|
|
xiep->v.mouse.button = ep->v.mouse.button;
|
|
break;
|
|
case E_MOUSE_DBL:
|
|
xiep->type = XinEventMouseDouble;
|
|
xiep->v.mouse.where.v = ep->v.mouse.where.v;
|
|
xiep->v.mouse.where.h = ep->v.mouse.where.h;
|
|
xiep->v.mouse.shift = ep->v.mouse.shift;
|
|
xiep->v.mouse.control = ep->v.mouse.control;
|
|
xiep->v.mouse.button = ep->v.mouse.button;
|
|
break;
|
|
case E_CHAR:
|
|
xiep->type = XinEventCharacter;
|
|
xiep->v.character.ch = ep->v.chr.ch;
|
|
#if XIWS == XIWS_WM
|
|
/* TODO ep->v.chr.shift and ep->v.chr.control are not set properly for
|
|
* XVT/CH */
|
|
xiep->v.character.shift = FALSE;
|
|
xiep->v.character.control = FALSE;
|
|
#else
|
|
xiep->v.character.shift = ep->v.chr.shift;
|
|
xiep->v.character.control = ep->v.chr.control;
|
|
#endif
|
|
#if XIWS == XIWS_WIN
|
|
if ( xiep->v.character.ch == '\t' && xiep->v.character.shift )
|
|
/* ignore bogus shift-tab from XVT */
|
|
retval = FALSE;
|
|
#endif
|
|
break;
|
|
case E_HSCROLL:
|
|
xiep->type = XinEventHScroll;
|
|
xiep->v.scroll.action = ConvertWhat( ep->v.scroll.what );
|
|
xiep->v.scroll.position = ep->v.scroll.pos;
|
|
break;
|
|
case E_VSCROLL:
|
|
xiep->type = XinEventVScroll;
|
|
xiep->v.scroll.action = ConvertWhat( ep->v.scroll.what );
|
|
xiep->v.scroll.position = ep->v.scroll.pos;
|
|
break;
|
|
case E_COMMAND:
|
|
xiep->type = XinEventMenuCommand;
|
|
xiep->v.menu_command.tag = ep->v.cmd.tag;
|
|
xiep->v.menu_command.shift = ep->v.cmd.shift;
|
|
xiep->v.menu_command.control = ep->v.cmd.control;
|
|
break;
|
|
case E_FONT:
|
|
xiep->type = XinEventFont;
|
|
xiep->v.font.font = XinFontXvtConvert( ep->v.font.font_id );
|
|
XinFontNativeConvert( xiep->v.font.font );
|
|
break;
|
|
case E_CONTROL:
|
|
xiep->type = XinEventControl;
|
|
xiep->v.control.control_id = ep->v.ctl.id;
|
|
switch ( ep->v.ctl.ci.type )
|
|
{
|
|
/* non-xvt versions do not need to support buttons, radio buttons,
|
|
* and check boxes */
|
|
case WC_PUSHBUTTON:
|
|
xiep->v.control.ctrl_info.type = XinWindowTypeButton;
|
|
break;
|
|
case WC_RADIOBUTTON:
|
|
xiep->v.control.ctrl_info.type = XinWindowTypeRadioButton;
|
|
break;
|
|
case WC_CHECKBOX:
|
|
xiep->v.control.ctrl_info.type = XinWindowTypeCheckBox;
|
|
break;
|
|
case WC_HSCROLL:
|
|
xiep->v.control.ctrl_info.win = ( XinWindow ) ep->v.ctl.ci.win;
|
|
xiep->v.control.ctrl_info.type = XinWindowTypeHorizontalScrollBar;
|
|
xiep->v.control.ctrl_info.v.scroll.action = ConvertWhat( ep->v.ctl.ci.v.scroll.what );
|
|
xiep->v.control.ctrl_info.v.scroll.position = ep->v.ctl.ci.v.scroll.pos;
|
|
break;
|
|
case WC_VSCROLL:
|
|
xiep->v.control.ctrl_info.win = ( XinWindow ) ep->v.ctl.ci.win;
|
|
xiep->v.control.ctrl_info.type = XinWindowTypeVerticalScrollBar;
|
|
xiep->v.control.ctrl_info.v.scroll.action = ConvertWhat( ep->v.ctl.ci.v.scroll.what );
|
|
xiep->v.control.ctrl_info.v.scroll.position = ep->v.ctl.ci.v.scroll.pos;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
case E_TIMER:
|
|
xiep->type = XinEventTimer;
|
|
xiep->v.timer.id = ep->v.timer.id;
|
|
break;
|
|
case E_QUIT:
|
|
xiep->type = XinEventQuit;
|
|
xiep->v.quit.query = ep->v.query;
|
|
break;
|
|
case E_HELP:
|
|
xiep->type = XinEventHelp;
|
|
xiep->v.help.obj = ( XinWindow ) ep->v.help.obj;
|
|
xiep->v.help.tag = ep->v.help.tag;
|
|
xiep->v.help.topic_id = ( long ) ep->v.help.tid;
|
|
break;
|
|
case E_USER:
|
|
xiep->type = XinEventUser;
|
|
xiep->v.user.id = ep->v.user.id;
|
|
xiep->v.user.ptr = ep->v.user.ptr;
|
|
break;
|
|
default:
|
|
retval = FALSE;
|
|
break;
|
|
}
|
|
return retval;
|
|
}
|
|
|
|
long
|
|
XinXvtEventHandler( WINDOW win, EVENT * ep )
|
|
{
|
|
WindowInfo *ehlt;
|
|
EVENT fake_event;
|
|
|
|
assert4( ep->type != E_CREATE || win != TASK_WIN || xin_teh != NULL, "",
|
|
20095, "XinAppSystemSetupInit was not provided." );
|
|
if ( ep->type == E_CREATE && xin_teh )
|
|
{
|
|
XinXvtWindowRegister( ( XinWindow ) win, xin_teh );
|
|
XinWindowCreateFinish( ( XinWindow ) win );
|
|
xin_teh = NULL;
|
|
}
|
|
|
|
/* Modal behavior */
|
|
#if XIWS == XIWS_MAC || XIWS == XIWS_XM || XIWS == XIWS_PM || XIWS == XIWS_WM || XIWS == XIWS_WXGTK
|
|
#if XIWS == XIWS_MAC
|
|
if ( xin_modal_win == ( XinWindow ) win
|
|
&& ep->type == E_FOCUS && !ep->v.active )
|
|
XinWindowFrontSet( xin_modal_win );
|
|
#else
|
|
if ( xin_modal_win != XI_NULL_WINDOW
|
|
&& ep->type == E_FOCUS
|
|
&& ep->v.active
|
|
&& xin_modal_win != ( XinWindow ) win )
|
|
XinWindowFrontSet( xin_modal_win );
|
|
#endif
|
|
if ( xin_modal_win != XI_NULL_WINDOW
|
|
&& ( XinWindow ) win != xin_modal_win
|
|
&& XinWindowParentGet( ( XinWindow ) win ) != xin_modal_win && ep->type != E_UPDATE
|
|
&& ep->type != E_TIMER )
|
|
return 0L;
|
|
#endif
|
|
/* Autoclose behavior */
|
|
if ( ( ( ep->type == E_FOCUS && !ep->v.active ) ||
|
|
( ep->type == E_CHAR && ep->v.chr.ch == '\033' ) ) &&
|
|
( WINDOW ) xin_autoclose_win == win )
|
|
{
|
|
MEMCLEAR( fake_event );
|
|
fake_event.type = E_CLOSE;
|
|
ep = &fake_event;
|
|
}
|
|
|
|
|
|
/* Font event */
|
|
if ( ep->type == E_COMMAND && ep->v.cmd.tag == XI_MENU_FONT_SELECT )
|
|
{
|
|
XVT_FNTID font_id;
|
|
|
|
font_id = xvt_dwin_get_font( win );
|
|
xvt_dm_post_font_sel( win, font_id, NULL, 0L );
|
|
xvt_font_destroy( font_id );
|
|
return 0L;
|
|
}
|
|
|
|
/* Help event - the user pressed F1 */
|
|
if (ep->type == E_HELP)
|
|
{ /* XVT sends the event to the task window. We want to redirect it to the focus window. */
|
|
win = (WINDOW)XinWindowFocusGet();
|
|
}
|
|
|
|
ehlt = find_window_info( win );
|
|
if ( ehlt != NULL )
|
|
{
|
|
XinEvent event;
|
|
|
|
MEMCLEAR( event );
|
|
|
|
if ( ConvertEvent( ep, &event ) )
|
|
{
|
|
EVENT* old_cur_event = cur_xvt_event;
|
|
|
|
cur_xvt_event = ep;
|
|
( *ehlt->event_handler ) ( ( XinWindow ) win, &event );
|
|
cur_xvt_event = old_cur_event;
|
|
if ( event.type == XinEventFont )
|
|
XinFontDestroy( event.v.font.font );
|
|
}
|
|
if ( ep->type == E_DESTROY )
|
|
deregister_window( win );
|
|
}
|
|
return 0L;
|
|
}
|
|
|
|
/*START*/
|
|
/*
|
|
this function creates a window or a scroll bar using the information in 'Def'.
|
|
*/
|
|
XinWindow
|
|
XinWindowCreate( XinWindowDef * Def )
|
|
{
|
|
/*END*/
|
|
WINDOW parent;
|
|
long flags;
|
|
WIN_TYPE win_type;
|
|
XinWindow win;
|
|
|
|
#if XIWS == XIWS_WIN || XIWS == XIWS_PM
|
|
int old_icon_rid;
|
|
|
|
#endif
|
|
|
|
switch ( Def->type )
|
|
{
|
|
case XinWindowTypeDocument:
|
|
if ( Def->parent == XI_NULL_WINDOW )
|
|
parent = TASK_WIN;
|
|
else
|
|
parent = ( WINDOW ) Def->parent;
|
|
flags = ( Def->close_button ? WSF_CLOSE : 0 ) |
|
|
( Def->horizontal_scroll_bar ? WSF_HSCROLL : 0 ) |
|
|
( Def->vertical_scroll_bar ? WSF_VSCROLL : 0 ) |
|
|
( Def->visible ? 0 : WSF_INVISIBLE ) |
|
|
( Def->enabled ? 0 : WSF_DISABLED ) |
|
|
( Def->maximized ? WSF_MAXIMIZED : 0 ) |
|
|
( Def->iconizable ? WSF_ICONIZABLE : 0 ) |
|
|
( Def->iconized ? WSF_ICONIZED : 0 );
|
|
#if XVT_CHECK_VERSION(4, 50, 0)
|
|
if ( Def->mode == XinModalWait )
|
|
{
|
|
win_type = W_MODAL;
|
|
if ( Def->close_button || Def->menu != NULL || Def->menu_bar_rid != 0 )
|
|
XinError( 20301, XinSeverityFatal, 0L );
|
|
}
|
|
else
|
|
#endif
|
|
switch ( Def->border_style )
|
|
{
|
|
case XinBorderSizable:
|
|
win_type = W_DOC;
|
|
flags |= WSF_SIZE;
|
|
break;
|
|
case XinBorderSingle:
|
|
win_type = W_PLAIN;
|
|
flags &= ~WSF_CLOSE;
|
|
break;
|
|
case XinBorderDouble:
|
|
win_type = W_DBL;
|
|
flags &= ~WSF_CLOSE;
|
|
break;
|
|
case XinBorderNone:
|
|
win_type = W_NO_BORDER;
|
|
flags &= ~WSF_CLOSE;
|
|
break;
|
|
case XinBorderFixed:
|
|
win_type = W_DOC;
|
|
break;
|
|
default:
|
|
win_type = W_DOC;
|
|
flags |= WSF_SIZE;
|
|
break;
|
|
}
|
|
if ( Def->menu == NULL && Def->menu_bar_rid == 0 )
|
|
flags |= WSF_NO_MENUBAR;
|
|
switch ( Def->mode )
|
|
{
|
|
case XinModalWait:
|
|
/* This is too clever. If we are in DSC45, then XinModalWait falls through
|
|
to the XinModalReturn case. */
|
|
#if XVT_CHECK_VERSION(4, 50, 0)
|
|
return XI_NULL_WINDOW;
|
|
#endif
|
|
xin_finish_create_def = Def;
|
|
/* don't break! We need to do the XinModalReturn stuff as well. */
|
|
case XinModalReturn:
|
|
if ( parent == TASK_WIN )
|
|
parent = SCREEN_WIN;
|
|
else
|
|
parent = TASK_WIN;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
#if XIWS == XIWS_WIN || XIWS == XIWS_PM
|
|
if ( Def->iconizable && Def->icon_rid != 0 )
|
|
{
|
|
old_icon_rid = ( int ) xvt_vobj_get_attr( NULL_WIN,
|
|
ATTR_WIN_PM_CLASS_ICON );
|
|
xvt_vobj_set_attr( NULL_WIN, ATTR_WIN_PM_CLASS_ICON, Def->icon_rid );
|
|
}
|
|
else
|
|
old_icon_rid = 0;
|
|
#endif
|
|
if ( Def->eh )
|
|
xin_teh = Def->eh;
|
|
xin_finish_create_menu = Def->menu;
|
|
#if XIWS == XIWS_WIN
|
|
if (parent == SCREEN_WIN)
|
|
xvt_vobj_set_attr( 0, ATTR_WIN_POPUP_DETACHED, TRUE );
|
|
#endif
|
|
win = ( XinWindow ) xvt_win_create( win_type, ( RCT * ) ( Def->p_rect ),
|
|
Def->title, Def->menu_bar_rid == 0 ? NULL_MENU_RID
|
|
: Def->menu_bar_rid, parent, flags, EM_ALL,
|
|
( EVENT_HANDLER ) XinXvtEventHandler, Def->app_data );
|
|
#if XIWS != XIWS_XM && XIWS != XIWS_WXGTK
|
|
#if XVT_CHECK_VERSION(4, 50, 0)
|
|
if ( Def->mode != XinModalWait && win != XI_NULL_WINDOW &&
|
|
xvt_vobj_is_valid( ( WINDOW ) win ) )
|
|
XinWindowFocusSet( win );
|
|
#endif
|
|
#endif
|
|
#if XIWS == XIWS_WIN || XIWS == XIWS_PM
|
|
if ( old_icon_rid != 0 )
|
|
xvt_vobj_set_attr( NULL_WIN, ATTR_WIN_PM_CLASS_ICON, old_icon_rid );
|
|
#endif
|
|
assert4( win, "", 20090, "create_window returned NULL" );
|
|
#if XVT_CHECK_VERSION(4, 50, 0)
|
|
if ( xvt_vobj_is_valid( ( WINDOW ) win ) )
|
|
{ /* We check because the window may have closed during its initial actions. */
|
|
#endif
|
|
switch ( Def->mode )
|
|
{
|
|
case XinModalReturn:
|
|
if ( Def->parent != XinWindowTaskGet( )
|
|
&& Def->parent != XinWindowScreenGet( ) )
|
|
{ /* Modal to parent only */
|
|
WindowInfo *info = find_window_info( ( WINDOW ) win );
|
|
|
|
assert4( info != NULL, "", 20091, "Window information corrupt" );
|
|
info->prev_modal = Def->parent;
|
|
XinWindowEnable( Def->parent, FALSE );
|
|
}
|
|
else if ( xin_modal_win != XI_NULL_WINDOW )
|
|
{ /* Nested modal */
|
|
WindowInfo *info = find_window_info( ( WINDOW ) win );
|
|
|
|
assert4( info != NULL, "", 20092, "Window information corrupt" );
|
|
info->prev_modal = xin_modal_win;
|
|
#if XIWS == XIWS_WIN || XIWS == XIWS_PM || XIWS == XIWS_WM || XIWS == XIWS_MAC
|
|
XinWindowEnable( xin_modal_win, FALSE );
|
|
#if XIWS == XIWS_MAC
|
|
XinWindowFrontSet( win );
|
|
#endif
|
|
#endif
|
|
xin_modal_win = win;
|
|
}
|
|
else
|
|
{
|
|
#if XIWS == XIWS_WIN || XIWS == XIWS_PM
|
|
XinWindowEnable( XinWindowTaskGet( ), FALSE );
|
|
#endif
|
|
xin_modal_win = win;
|
|
#if XIWS == XIWS_WM || XIWS == XIWS_MAC
|
|
{
|
|
SLIST win_list = xvt_scr_list_wins( );
|
|
SLIST_ELT elt;
|
|
|
|
for ( elt = xvt_slist_get_first( win_list ); elt != NULL;
|
|
elt = xvt_slist_get_next( win_list, elt ) )
|
|
if ( ( XinWindow ) * xvt_slist_get_data( elt ) != xin_modal_win )
|
|
XinWindowEnable( ( XinWindow ) * xvt_slist_get_data( elt ), FALSE );
|
|
xvt_slist_destroy( win_list );
|
|
}
|
|
#endif
|
|
}
|
|
break;
|
|
case XinModalAutoclose:
|
|
xin_autoclose_win = win;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
#if XVT_CHECK_VERSION(4, 50, 0)
|
|
}
|
|
#endif
|
|
return win;
|
|
case XinWindowTypeButton:
|
|
case XinWindowTypeRadioButton:
|
|
case XinWindowTypeCheckBox:
|
|
case XinWindowTypeHorizontalScrollBar:
|
|
case XinWindowTypeVerticalScrollBar:
|
|
{
|
|
WIN_DEF ctl_def;
|
|
|
|
#if XVT_CHECK_VERSION(4, 50, 0)
|
|
XVT_COLOR_COMPONENT colors[8];
|
|
|
|
#endif
|
|
MEMCLEAR( ctl_def );
|
|
switch ( Def->type )
|
|
{
|
|
case XinWindowTypeButton:
|
|
ctl_def.wtype = WC_PUSHBUTTON;
|
|
break;
|
|
case XinWindowTypeRadioButton:
|
|
ctl_def.wtype = WC_RADIOBUTTON;
|
|
break;
|
|
case XinWindowTypeCheckBox:
|
|
ctl_def.wtype = WC_CHECKBOX;
|
|
break;
|
|
case XinWindowTypeHorizontalScrollBar:
|
|
Def->title = "";
|
|
ctl_def.wtype = WC_HSCROLL;
|
|
break;
|
|
case XinWindowTypeVerticalScrollBar:
|
|
Def->title = "";
|
|
ctl_def.wtype = WC_VSCROLL;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
flags = ( Def->visible ? 0 : CTL_FLAG_INVISIBLE );
|
|
if ( !Def->enabled )
|
|
flags |= CTL_FLAG_DISABLED;
|
|
ctl_def.rct = *( RCT * ) Def->p_rect;
|
|
ctl_def.text = Def->title;
|
|
ctl_def.v.ctl.ctrl_id = Def->control_id;
|
|
ctl_def.v.ctl.flags = flags;
|
|
#if XVT_CHECK_VERSION(4, 50, 0)
|
|
if ( Def->back_color )
|
|
{
|
|
colors[0].type = XVT_COLOR_BLEND;
|
|
colors[0].color = Def->back_color;
|
|
colors[1].type = XVT_COLOR_NULL;
|
|
ctl_def.ctlcolors = colors;
|
|
}
|
|
if ( Def->font )
|
|
ctl_def.v.ctl.font_id = Def->font->xvt_fntid;
|
|
#endif
|
|
return ( XinWindow ) xvt_ctl_create_def( &ctl_def, ( WINDOW ) Def->parent, 0L );
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
return 0L;
|
|
/*START*/
|
|
}
|
|
|
|
/* This function is called when the create event for a window comes thru.
|
|
Other higher level stuff depends on this being done before any events
|
|
for the window are passed on. */
|
|
|
|
void
|
|
XinWindowCreateFinish( XinWindow win )
|
|
{
|
|
/*END*/
|
|
#if XIWS == XIWS_PM
|
|
{
|
|
HWND hwnd = ( HWND ) xvt_vobj_get_attr( ( WINDOW ) win, ATTR_NATIVE_WINDOW );
|
|
|
|
if ( hwnd && old_pm_proc == NULL )
|
|
old_pm_proc = WinSubclassWindow( hwnd, pm_proc );
|
|
}
|
|
#endif
|
|
if ( xin_finish_create_menu != NULL )
|
|
XinWindowMenuReplace( win, 0, xin_finish_create_menu );
|
|
xvt_vobj_set_attr( NULL_WIN, ATTR_SUPPRESS_UPDATE_CHECK, ( long ) TRUE );
|
|
|
|
if ( xin_finish_create_def != NULL )
|
|
{
|
|
XinWindowDef * Def = xin_finish_create_def;
|
|
if ( Def->parent != XinWindowTaskGet( )
|
|
&& Def->parent != XinWindowScreenGet( ) )
|
|
{ /* Modal to parent only */
|
|
WindowInfo *info = find_window_info( ( WINDOW ) win );
|
|
|
|
assert4( info != NULL, "", 20091, "Window information corrupt" );
|
|
info->prev_modal = Def->parent;
|
|
XinWindowEnable( Def->parent, FALSE );
|
|
}
|
|
else if ( xin_modal_win != XI_NULL_WINDOW )
|
|
{ /* Nested modal */
|
|
WindowInfo *info = find_window_info( ( WINDOW ) win );
|
|
|
|
assert4( info != NULL, "", 20092, "Window information corrupt" );
|
|
info->prev_modal = xin_modal_win;
|
|
#if XIWS == XIWS_WIN || XIWS == XIWS_PM || XIWS == XIWS_WM || XIWS == XIWS_MAC
|
|
XinWindowEnable( xin_modal_win, FALSE );
|
|
#if XIWS == XIWS_MAC
|
|
XinWindowFrontSet( win );
|
|
#endif
|
|
#endif
|
|
xin_modal_win = win;
|
|
}
|
|
else
|
|
{
|
|
#if XIWS == XIWS_WIN || XIWS == XIWS_PM
|
|
XinWindowEnable( XinWindowTaskGet( ), FALSE );
|
|
#endif
|
|
xin_modal_win = win;
|
|
#if XIWS == XIWS_WM || XIWS == XIWS_MAC
|
|
{
|
|
SLIST win_list = xvt_scr_list_wins( );
|
|
SLIST_ELT elt;
|
|
|
|
for ( elt = xvt_slist_get_first( win_list ); elt != NULL;
|
|
elt = xvt_slist_get_next( win_list, elt ) )
|
|
if ( ( XinWindow ) * xvt_slist_get_data( elt ) != xin_modal_win )
|
|
XinWindowEnable( ( XinWindow ) * xvt_slist_get_data( elt ), FALSE );
|
|
xvt_slist_destroy( win_list );
|
|
}
|
|
#endif
|
|
}
|
|
xin_finish_create_def = NULL;
|
|
}
|
|
/*START*/
|
|
}
|
|
|
|
/*END*/
|
|
#if XIWS != XIWS_WM
|
|
static CURSOR
|
|
XinCursorToCURSOR( XinCursor Cursor )
|
|
{
|
|
switch ( Cursor )
|
|
{
|
|
case XI_CURSOR_ARROW:
|
|
return CURSOR_ARROW;
|
|
case XI_CURSOR_IBEAM:
|
|
return CURSOR_IBEAM;
|
|
case XI_CURSOR_CROSS:
|
|
return CURSOR_CROCE;
|
|
}
|
|
return ( CURSOR ) Cursor;
|
|
}
|
|
|
|
#endif
|
|
|
|
/*START*/
|
|
/*
|
|
this function sets the current cursor. the argument 'Cursor' can be:
|
|
XI_CURSOR_ARROW the ubiquitous arrow cursor
|
|
XI_CURSOR_IBEAM ibeam insertion point for edit controls
|
|
XI_CURSOR_CROSS a plus sign cursor (crosshairs)
|
|
XI_CURSOR_RESIZE horizontal resize
|
|
XI_CURSOR_HAND hand cursor (for moving columns in a list)
|
|
XI_CURSOR_VRESIZE vertical resize
|
|
|
|
when the cursor is set, it remains in that state until the cursor is changed
|
|
by another call to this function. an exception is when XinCursorWait is called.
|
|
this changes the cursor to the waiting cursor (usually an hourglass), indicating that
|
|
the application
|
|
is busy. as soon as the event handler that is currently being processed returns,
|
|
then the cursor changes back to the current cursor (i.e. whatever cursor was
|
|
set the last time that XinWindowCursorSet was called)
|
|
*/
|
|
void
|
|
XinWindowCursorSet( XinWindow win, XinCursor Cursor )
|
|
{
|
|
/*END*/
|
|
#if XIWS != XIWS_WM
|
|
xvt_win_set_cursor( ( WINDOW ) win, XinCursorToCURSOR( Cursor ) );
|
|
#else
|
|
NOREF( win );
|
|
NOREF( Cursor );
|
|
#endif
|
|
/*START*/
|
|
}
|
|
|
|
/*
|
|
this function destroys a previously created XinWindow. The XinWindow could either
|
|
be a top level window, or a scroll bar.
|
|
*/
|
|
void
|
|
XinWindowDestroy( XinWindow win )
|
|
{
|
|
/*END*/
|
|
WindowInfo *info = find_window_info( ( WINDOW ) win );
|
|
|
|
if ( win == xin_autoclose_win )
|
|
xin_autoclose_win = XI_NULL_WINDOW;
|
|
if ( app_terminating )
|
|
return;
|
|
if ( info != NULL )
|
|
{
|
|
if ( win == xin_modal_win )
|
|
{
|
|
xin_modal_win = info->prev_modal;
|
|
if ( xin_modal_win == XI_NULL_WINDOW )
|
|
{ /* Last modal window closed */
|
|
#if XIWS == XIWS_WIN || XIWS == XIWS_PM
|
|
XinWindowEnable( XinWindowTaskGet( ), TRUE );
|
|
#elif XIWS == XIWS_WM || XIWS == XIWS_MAC
|
|
{
|
|
SLIST win_list = xvt_scr_list_wins( );
|
|
SLIST_ELT elt;
|
|
|
|
for ( elt = xvt_slist_get_first( win_list ); elt != NULL;
|
|
elt = xvt_slist_get_next( win_list, elt ) )
|
|
XinWindowEnable( ( XinWindow ) * xvt_slist_get_data( elt ), TRUE );
|
|
xvt_slist_destroy( win_list );
|
|
}
|
|
#endif
|
|
}
|
|
else
|
|
{ /* Top nested window closed */
|
|
#if XIWS == XIWS_WIN || XIWS == XIWS_PM || XIWS == XIWS_WM || XIWS == XIWS_MAC
|
|
XinWindowEnable( xin_modal_win, TRUE );
|
|
#if XIWS != XIWS_WIN
|
|
XinWindowFrontSet( xin_modal_win );
|
|
#endif
|
|
#endif
|
|
}
|
|
}
|
|
else if ( xin_modal_win != XI_NULL_WINDOW || info->prev_modal != XI_NULL_WINDOW )
|
|
{ /* Window is not top modal window */
|
|
WindowInfo *cur_info;
|
|
XinWindow cur_win = xin_modal_win;
|
|
|
|
if ( cur_win != XI_NULL_WINDOW )
|
|
{
|
|
do
|
|
{
|
|
cur_info = find_window_info( ( WINDOW ) cur_win );
|
|
assert4( cur_info != NULL, "", 20094, "Window information corrupt" );
|
|
cur_win = cur_info->prev_modal;
|
|
} while ( cur_win != XI_NULL_WINDOW && cur_win != win );
|
|
}
|
|
/* If cur_win is not null, then remove this window from the modal list.
|
|
* Otherwise, if there is a prev_modal link, the window is a parented
|
|
* modal. */
|
|
if ( cur_win != XI_NULL_WINDOW )
|
|
cur_info->prev_modal = info->prev_modal;
|
|
else if ( info->prev_modal != XI_NULL_WINDOW )
|
|
XinWindowEnable( info->prev_modal, TRUE );
|
|
}
|
|
}
|
|
xvt_vobj_destroy( ( WINDOW ) win );
|
|
/*START*/
|
|
}
|
|
|
|
/*END*/
|
|
static DRAW_MODE
|
|
DrawModeToMODE( XinDrawMode Mode )
|
|
{
|
|
switch ( Mode )
|
|
{
|
|
case XinDrawModeCopy:
|
|
return M_COPY;
|
|
case XinDrawModeXor:
|
|
return M_XOR;
|
|
}
|
|
return M_COPY;
|
|
}
|
|
|
|
static XinDrawMode
|
|
MODEToDrawMode( DRAW_MODE Mode )
|
|
{
|
|
switch ( Mode )
|
|
{
|
|
case M_COPY:
|
|
return XinDrawModeCopy;
|
|
case M_XOR:
|
|
return XinDrawModeXor;
|
|
default:
|
|
break;
|
|
}
|
|
return XinDrawModeCopy;
|
|
}
|
|
|
|
/*START*/
|
|
/*
|
|
this function sets the drawing mode to XinDrawModeCopy or XinDrawModeXor.
|
|
see the discussion above on drawing modes.
|
|
*/
|
|
void
|
|
XinWindowDrawModeSet( XinWindow win, XinDrawMode mode )
|
|
{
|
|
/*END*/
|
|
xvt_dwin_set_draw_mode( ( WINDOW ) win, DrawModeToMODE( mode ) );
|
|
/*START*/
|
|
}
|
|
|
|
/*
|
|
this function gets the currently set drawing tools. see the discussion above
|
|
on drawing tools for more information.
|
|
*/
|
|
XinDrawTools *
|
|
XinWindowDrawToolsGet( XinWindow win, XinDrawTools * DrawTools )
|
|
{
|
|
/*END*/
|
|
DRAW_CTOOLS ct;
|
|
|
|
xvt_dwin_get_draw_ctools( ( WINDOW ) win, &ct );
|
|
DrawTools->pen.fore_color = ct.pen.color;
|
|
DrawTools->pen.pattern = PATToPenPattern( ct.pen.pat );
|
|
DrawTools->pen.width = ct.pen.width;
|
|
DrawTools->brush.fore_color = ct.brush.color;
|
|
DrawTools->brush.pattern = PATToBrushPattern( ct.brush.pat );
|
|
DrawTools->draw_mode = MODEToDrawMode( ct.mode );
|
|
DrawTools->opaque_text = ct.opaque_text;
|
|
DrawTools->text_fore_color = ct.fore_color;
|
|
DrawTools->text_back_color = ct.back_color;
|
|
return DrawTools;
|
|
/*START*/
|
|
}
|
|
|
|
/*
|
|
this function gets the currently drawing mode. see the discussion above
|
|
on drawing mode for more information.
|
|
*/
|
|
XinDrawMode
|
|
XinWindowDrawModeGet( XinWindow win )
|
|
{
|
|
/*END*/
|
|
DRAW_CTOOLS ct;
|
|
XinDrawMode mode;
|
|
|
|
xvt_dwin_get_draw_ctools( ( WINDOW ) win, &ct );
|
|
mode = MODEToDrawMode( ct.mode );
|
|
return mode;
|
|
/*START*/
|
|
}
|
|
|
|
/*
|
|
this function gets an XinDrawTools that is a common configuration. the
|
|
common configuration consists of a black pen of width of 1 pixel, a solid
|
|
black brush, copy mode, foreground text color of black, background text color
|
|
of white, and non-opaque text.
|
|
|
|
the implementation below is complete.
|
|
*/
|
|
XinDrawTools *
|
|
XinWindowDrawToolsNormalGet( XinDrawTools * ct )
|
|
{
|
|
ct->pen.width = 1;
|
|
ct->pen.pattern = XinPenSolid;
|
|
ct->pen.fore_color = XI_COLOR_BLACK;
|
|
ct->brush.pattern = XinBrushSolid;
|
|
ct->brush.fore_color = XI_COLOR_BLACK;
|
|
ct->draw_mode = XinDrawModeCopy;
|
|
ct->text_fore_color = XI_COLOR_BLACK;
|
|
ct->text_back_color = XI_COLOR_WHITE;
|
|
ct->opaque_text = FALSE;
|
|
return ct;
|
|
}
|
|
|
|
/*
|
|
this function sets the current drawing tools. the drawing tools may have been
|
|
defined by the user of Xin. or they may have been gotten from a call to
|
|
XinWindowDrawToolsNormalGet, or they may have been gotten from a call to
|
|
XinWindowDrawToolsGet.
|
|
*/
|
|
void
|
|
XinWindowDrawToolsSet( XinWindow win, XinDrawTools * ct )
|
|
{
|
|
/*END*/
|
|
#if XIWS == XIWS_WM
|
|
{
|
|
DRAW_CTOOLS xct;
|
|
|
|
xct.pen.color = ct->pen.fore_color;
|
|
xi_fix_color( &xct.pen.color );
|
|
xct.pen.pat = ct->pen.pattern;
|
|
xct.pen.width = ct->pen.width;
|
|
xct.pen.style = P_SOLID;
|
|
xct.brush.color = ct->brush.fore_color;
|
|
xi_fix_color( &xct.brush.color );
|
|
xct.brush.pat = ct->brush.pattern;
|
|
xct.mode = DrawModeToMODE( ct->draw_mode );
|
|
xct.opaque_text = ct->opaque_text;
|
|
xct.fore_color = ct->text_fore_color;
|
|
xi_fix_color( &xct.fore_color );
|
|
xct.back_color = ct->text_back_color;
|
|
xi_fix_color( &xct.back_color );
|
|
xvt_dwin_set_draw_ctools( ( WINDOW ) win, &xct );
|
|
}
|
|
#else
|
|
{
|
|
DRAW_CTOOLS xct;
|
|
|
|
xct.pen.color = ct->pen.fore_color;
|
|
xct.pen.pat = PenPatternToPAT( ct->pen.pattern );
|
|
xct.pen.width = ct->pen.width;
|
|
switch ( ct->pen.pattern )
|
|
{
|
|
case XinPenSolid:
|
|
case XinPenHollow:
|
|
xct.pen.style = P_SOLID;
|
|
break;
|
|
case XinPenDashed:
|
|
xct.pen.style = P_DASH;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
xct.brush.color = ct->brush.fore_color;
|
|
xct.brush.pat = BrushPatternToPAT( ct->brush.pattern );
|
|
xct.mode = DrawModeToMODE( ct->draw_mode );
|
|
xct.opaque_text = ct->opaque_text;
|
|
xct.fore_color = ct->text_fore_color;
|
|
xct.back_color = ct->text_back_color;
|
|
xvt_dwin_set_draw_ctools( ( WINDOW ) win, &xct );
|
|
}
|
|
#endif
|
|
/*START*/
|
|
}
|
|
|
|
/*
|
|
this function draws an ellipse in the specified window, following the state of
|
|
clipping, pens, brushes, and copy mode. see the drawing discussion above for
|
|
more details.
|
|
*/
|
|
void
|
|
XinWindowEllipseDraw( XinWindow Win, XinRect * rctp )
|
|
{
|
|
/*END*/
|
|
RCT r;
|
|
|
|
r.left = rctp->left;
|
|
r.top = rctp->top;
|
|
r.right = rctp->right;
|
|
r.bottom = rctp->bottom;
|
|
xvt_dwin_draw_oval( ( WINDOW ) Win, &r );
|
|
/*START*/
|
|
}
|
|
|
|
/*
|
|
this function sets the enabled state of a window. see the discussion on
|
|
windows above for information on enabling and disabling windows.
|
|
*/
|
|
void
|
|
XinWindowEnable( XinWindow Win, BOOLEAN Enable )
|
|
{
|
|
/*END*/
|
|
xvt_vobj_set_enabled( ( WINDOW ) Win, Enable );
|
|
/*START*/
|
|
}
|
|
|
|
/*
|
|
this function causes an XinEventUser to be sent to the window. for the
|
|
MFC implementation, this function simply declares an XinEvent, clears the
|
|
event, sets the 'id' and 'ptr' fields in the XinEvent, and calls the
|
|
event handler for the window.
|
|
*/
|
|
void
|
|
XinWindowEventUserSend( XinWindow win, long id, void *ptr )
|
|
{
|
|
/*END*/
|
|
EVENT event;
|
|
|
|
event.type = E_USER;
|
|
event.v.user.id = id;
|
|
event.v.user.ptr = ptr;
|
|
XinXvtEventHandler( ( WINDOW ) win, &event );
|
|
/*START*/
|
|
}
|
|
|
|
/*
|
|
this function maps a font to a previously created XinWindow.
|
|
*/
|
|
void
|
|
XinWindowFontMap( XinWindow Win, XinFont * Font )
|
|
{
|
|
/*END*/
|
|
xvt_font_map( Font->xvt_fntid, ( WINDOW ) Win );
|
|
/*START*/
|
|
}
|
|
|
|
void
|
|
XinFontUnmap( XinFont * font )
|
|
{
|
|
xvt_font_unmap( font->xvt_fntid );
|
|
}
|
|
|
|
/*
|
|
this function returns the window with the current keyboard focus.
|
|
normally, this is the top window.
|
|
*/
|
|
XinWindow
|
|
XinWindowFocusGet( void )
|
|
{
|
|
/*END*/
|
|
return ( XinWindow ) xvt_scr_get_focus_topwin( );
|
|
/*START*/
|
|
}
|
|
|
|
/*
|
|
this function makes the specified window have the keyboard focus. it
|
|
doesn't change which window is on top.
|
|
*/
|
|
void
|
|
XinWindowFocusSet( XinWindow Win )
|
|
{
|
|
/*END*/
|
|
xvt_scr_set_focus_vobj( ( WINDOW ) Win );
|
|
/*START*/
|
|
}
|
|
|
|
/*
|
|
this function makes the specified window be the top window.
|
|
*/
|
|
void
|
|
XinWindowFrontSet( XinWindow Win )
|
|
{
|
|
/*END*/
|
|
xvt_vobj_raise( ( WINDOW ) Win );
|
|
/*START*/
|
|
}
|
|
|
|
void
|
|
XinWindowHotkeySet( XinWindow win, char ch )
|
|
{
|
|
NOREF( win );
|
|
NOREF( ch );
|
|
}
|
|
|
|
/*
|
|
this function draws the icon specifed by the resource id in 'IconRid' in the
|
|
specified window. the MFC implementation ignores the fore_color and back_color
|
|
because the icons have colors. fore_color and back_color are only used
|
|
on GUIs where icons might be black and white, such as X/Motif. 'x' and
|
|
'y' specify the position where the icon is drawn.
|
|
*/
|
|
void
|
|
XinWindowIconDraw( XinWindow Win, int x, int y, int IconRid,
|
|
XinColor fore_color, XinColor back_color )
|
|
{
|
|
/*END*/
|
|
#if XIWS == XIWS_WM
|
|
NOREF( Win );
|
|
NOREF( x );
|
|
NOREF( y );
|
|
NOREF( IconRid );
|
|
NOREF( fore_color );
|
|
NOREF( back_color );
|
|
#else
|
|
#if XIWS == XIWS_XM || XIWS == XIWS_MAC || XIWS == XIWS_WXGTK
|
|
if ( fore_color )
|
|
xvt_dwin_set_fore_color( ( WINDOW ) Win, fore_color );
|
|
if ( back_color )
|
|
xvt_dwin_set_back_color( ( WINDOW ) Win, back_color );
|
|
#else
|
|
NOREF( fore_color );
|
|
NOREF( back_color );
|
|
#endif
|
|
/*** Hack for PM only 08/96 XVT 4.02 */
|
|
#if XIWS == XIWS_PM
|
|
{
|
|
XinDrawTools new_ctools;
|
|
XinDrawTools save_ctools;
|
|
|
|
new_ctools.pen.width = 1;
|
|
new_ctools.pen.fore_color = XI_COLOR_BLACK;
|
|
new_ctools.pen.pattern = XinPenSolid;
|
|
|
|
new_ctools.brush.pattern = XinBrushSolid;
|
|
new_ctools.brush.fore_color = XI_COLOR_BLACK;
|
|
|
|
new_ctools.draw_mode = XinDrawModeCopy;
|
|
|
|
new_ctools.opaque_text = TRUE;
|
|
new_ctools.text_fore_color = fore_color;
|
|
new_ctools.text_back_color = back_color;
|
|
|
|
XinWindowDrawToolsGet( Win, &save_ctools );
|
|
XinWindowDrawToolsSet( Win, &new_ctools );
|
|
{
|
|
RCT r;
|
|
|
|
r.top = y;
|
|
r.left = x;
|
|
r.bottom = y + 1;
|
|
r.right = x + 1;
|
|
xvt_dwin_draw_rect( ( WINDOW ) Win, &r );
|
|
}
|
|
XinWindowDrawToolsSet( Win, &save_ctools );
|
|
}
|
|
#endif
|
|
xvt_dwin_draw_icon( ( WINDOW ) Win, x, y, IconRid );
|
|
#endif
|
|
/*START*/
|
|
}
|
|
|
|
/*END*/
|
|
static XinPoint save_move_to;
|
|
|
|
/*START*/
|
|
/*
|
|
this function draws a line from the point previously passed to XinWindowLineMoveTo
|
|
or the point in the last XinWindowLineDraw call
|
|
to the point passed to this function. this function obeys the state in the
|
|
draw tools (or the functions that set the individual components of drawing tools).
|
|
the state that affects line drawing is the draw mode and pen.
|
|
*/
|
|
void
|
|
XinWindowLineDraw( XinWindow Win, XinPoint * pnt )
|
|
{
|
|
/*END*/
|
|
PNT mtp,
|
|
mpnt;
|
|
|
|
mtp.v = save_move_to.v;
|
|
mtp.h = save_move_to.h;
|
|
mpnt.v = pnt->v;
|
|
mpnt.h = pnt->h;
|
|
|
|
if ( mtp.v != mpnt.v && mtp.h != mpnt.h )
|
|
{
|
|
if ( mtp.h > mpnt.h )
|
|
{
|
|
PNT tpnt;
|
|
|
|
tpnt = mtp;
|
|
mtp = mpnt;
|
|
mpnt = tpnt;
|
|
}
|
|
#if XIWS == XIWS_PM
|
|
if ( mtp.v > mpnt.v )
|
|
{
|
|
mtp.v--;
|
|
mpnt.h--;
|
|
}
|
|
else
|
|
{
|
|
mpnt.v--;
|
|
mpnt.h--;
|
|
}
|
|
#elif XIWS == XIWS_MAC
|
|
if ( mtp.v > mpnt.v )
|
|
{
|
|
mpnt.h--;
|
|
mpnt.v++;
|
|
}
|
|
else
|
|
{
|
|
mtp.v++;
|
|
mpnt.h--;
|
|
}
|
|
mtp.v--;
|
|
mpnt.v--;
|
|
#elif XIWS == XIWS_WIN
|
|
if ( mtp.v > mpnt.v )
|
|
{
|
|
mpnt.v--;
|
|
mtp.v--;
|
|
}
|
|
#elif XIWS == XIWS_XM || XIWS == XIWS_WXGTK
|
|
if ( mtp.v > mpnt.v )
|
|
{
|
|
mpnt.h--;
|
|
mtp.v--;
|
|
}
|
|
else
|
|
{
|
|
mpnt.h--;
|
|
mpnt.v--;
|
|
}
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
#if XIWS == XIWS_MAC || XIWS == XIWS_XM || XIWS == XIWS_PM || XIWS == XIWS_WXGTK
|
|
if ( mtp.v == mpnt.v )
|
|
--mpnt.h;
|
|
if ( mtp.h == mpnt.h )
|
|
--mpnt.v;
|
|
#endif
|
|
}
|
|
xvt_dwin_draw_set_pos( ( WINDOW ) Win, mtp );
|
|
xvt_dwin_draw_line( ( WINDOW ) Win, mpnt );
|
|
save_move_to = *pnt;
|
|
/*START*/
|
|
}
|
|
|
|
/*
|
|
the user of Xin calls this function just prior to calling XinWindowLineDraw,
|
|
to specify the starting point for drawing a line.
|
|
*/
|
|
void
|
|
XinWindowLineMoveTo( XinWindow Win, XinPoint * pnt )
|
|
{
|
|
/*END*/
|
|
NOREF( Win );
|
|
save_move_to = *pnt;
|
|
/*START*/
|
|
}
|
|
|
|
/*
|
|
if a menu item is checkable, then this function checks or un-checks the menu
|
|
item.
|
|
*/
|
|
void
|
|
XinWindowMenuItemCheck( XinWindow Win, XinMenuTag Tag, BOOLEAN check )
|
|
{
|
|
/*END*/
|
|
xvt_menu_set_item_checked( ( WINDOW ) Win, ( MENU_TAG ) Tag, check );
|
|
/*START*/
|
|
}
|
|
|
|
/*
|
|
this function enables or disables a menu item.
|
|
*/
|
|
void
|
|
XinWindowMenuItemEnable( XinWindow Win, XinMenuTag Tag, BOOLEAN Enable )
|
|
{
|
|
/*END*/
|
|
xvt_menu_set_item_enabled( ( WINDOW ) Win, ( MENU_TAG ) Tag, Enable );
|
|
/*START*/
|
|
}
|
|
|
|
/*
|
|
this function sets the checked font in the font selection dialog box to the
|
|
specified font. the next time that the font selection dialog is put up,
|
|
it will reflect the effects of the call to this function.
|
|
*/
|
|
void
|
|
XinWindowMenuFontSet( XinWindow win, XinFont * fontp )
|
|
{
|
|
/*END*/
|
|
xvt_menu_set_font_sel( ( WINDOW ) win, fontp->xvt_fntid );
|
|
/*START*/
|
|
}
|
|
|
|
/*END*/
|
|
static XinMenuItem *copy_menu_items( MENU_ITEM * items, int *p_nbr_children );
|
|
|
|
static char *
|
|
copy_xvt_menu_text( char *text, char mnemonic )
|
|
{
|
|
char *new_text;
|
|
char *from;
|
|
char *to;
|
|
int size = strlen( text ) + 2;
|
|
|
|
new_text = to = XinMemoryAlloc( size );
|
|
for ( from = text; *from != '\0'; )
|
|
{
|
|
if ( *from == mnemonic )
|
|
{
|
|
*to++ = '~';
|
|
mnemonic = '\0';
|
|
}
|
|
*to++ = *from++;
|
|
}
|
|
*to = '\0';
|
|
return new_text;
|
|
}
|
|
|
|
static void
|
|
copy_menu_item( XinMenuItem * new_item, MENU_ITEM * item )
|
|
{
|
|
new_item->tag = item->tag;
|
|
if ( item->text == NULL )
|
|
new_item->text = NULL;
|
|
else
|
|
new_item->text = copy_xvt_menu_text( item->text, ( char ) item->mkey );
|
|
new_item->enabled = item->enabled;
|
|
new_item->checked = item->checked;
|
|
new_item->checkable = item->checkable;
|
|
new_item->separator = item->separator;
|
|
if ( item->child == 0 )
|
|
{
|
|
new_item->nbr_children = 0;
|
|
new_item->children = NULL;
|
|
}
|
|
else
|
|
new_item->children = copy_menu_items( item->child,
|
|
&new_item->nbr_children );
|
|
}
|
|
|
|
static XinMenuItem *
|
|
copy_menu_items( MENU_ITEM * items, int *p_nbr_children )
|
|
{
|
|
MENU_ITEM *item;
|
|
XinMenuItem *new_items;
|
|
XinMenuItem *new_item;
|
|
int count;
|
|
|
|
count = 0;
|
|
for ( item = items; item->tag != 0; item++, count++ )
|
|
;
|
|
*p_nbr_children = count;
|
|
if ( count == 0 )
|
|
return new_items = NULL;
|
|
else
|
|
{
|
|
new_items = XinMemoryAlloc( count * sizeof( XinMenuItem ) );
|
|
for ( item = items, new_item = new_items; item->tag != 0;
|
|
item++, new_item++ )
|
|
copy_menu_item( new_item, item );
|
|
}
|
|
return new_items;
|
|
}
|
|
|
|
static XinMenu *
|
|
make_menu( MENU_ITEM * items )
|
|
{
|
|
XinMenu *menu = XinMemoryAlloc( sizeof( XinMenu ) );
|
|
|
|
menu->items = copy_menu_items( items, &menu->nbr_items );
|
|
return menu;
|
|
}
|
|
|
|
static MENU_ITEM *make_xvt_menu( int nbr_items, XinMenuItem * items );
|
|
|
|
static void
|
|
xvt_menu_set_text( MENU_ITEM * item, char *text )
|
|
{
|
|
char *from;
|
|
char *to;
|
|
int size = strlen( text ) + 1;
|
|
|
|
item->text = xvt_mem_alloc( size );
|
|
for ( from = text, to = item->text; *from != '\0'; )
|
|
{
|
|
if ( *from == '~' )
|
|
{
|
|
from++;
|
|
item->mkey = *from;
|
|
}
|
|
else
|
|
*to++ = *from++;
|
|
}
|
|
*to = '\0';
|
|
}
|
|
|
|
static void
|
|
copy_item_to_xvt( MENU_ITEM * new_item, XinMenuItem * item )
|
|
{
|
|
if ( item->text == NULL )
|
|
new_item->text = NULL;
|
|
else
|
|
xvt_menu_set_text( new_item, item->text );
|
|
new_item->tag = item->tag;
|
|
new_item->enabled = item->enabled;
|
|
new_item->checked = item->checked;
|
|
new_item->checkable = item->checkable;
|
|
new_item->separator = item->separator;
|
|
if ( item->nbr_children == 0 )
|
|
new_item->child = NULL;
|
|
else
|
|
new_item->child = make_xvt_menu( item->nbr_children, item->children );
|
|
}
|
|
|
|
static MENU_ITEM *
|
|
make_xvt_menu( int nbr_items, XinMenuItem * items )
|
|
{
|
|
MENU_ITEM *xvt_menu;
|
|
XinMenuItem *item;
|
|
MENU_ITEM *new_item;
|
|
int num;
|
|
|
|
if ( nbr_items == 0 )
|
|
return NULL;
|
|
xvt_menu = ( MENU_ITEM * ) xvt_mem_zalloc( ( nbr_items + 1 )
|
|
* sizeof( MENU_ITEM ) );
|
|
for ( num = 0, item = items, new_item = xvt_menu; num < nbr_items;
|
|
item++, new_item++, num++ )
|
|
copy_item_to_xvt( new_item, item );
|
|
return xvt_menu;
|
|
}
|
|
|
|
static MENU_ITEM *
|
|
find_item( MENU_ITEM * tree, XinMenuTag tag )
|
|
{
|
|
MENU_ITEM *item;
|
|
|
|
for ( item = tree; item->tag != 0; item++ )
|
|
{
|
|
if ( item->tag == tag )
|
|
return item;
|
|
if ( item->child != NULL )
|
|
{
|
|
MENU_ITEM *sub_item = find_item( item->child, tag );
|
|
|
|
if ( sub_item != NULL )
|
|
return sub_item;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/*START*/
|
|
/*
|
|
this function returns an XinMenu tree for an existing menu. if tag == 0 then
|
|
this function returns the entire menu hierarchy. if tag != 0, then this function
|
|
returns the XinMenu tree from the menu item with the specified tag through to
|
|
the tips of the branches.
|
|
|
|
the returned XinMenu has been allocated on the heap, and will need to be freed
|
|
by a call to XinMenuDelete.
|
|
*/
|
|
XinMenu *
|
|
XinWindowMenuGet( XinWindow win, XinMenuTag tag )
|
|
{
|
|
/*END*/
|
|
MENU_ITEM *item;
|
|
XinMenu *menu;
|
|
MENU_ITEM *tree = xvt_menu_get_tree( ( WINDOW ) win );
|
|
|
|
if ( tag == 0 )
|
|
menu = make_menu( tree );
|
|
else
|
|
{
|
|
item = find_item( tree, tag );
|
|
if ( item->child == 0 )
|
|
menu = NULL;
|
|
else
|
|
menu = make_menu( item->child );
|
|
}
|
|
xvt_res_free_menu_tree( tree );
|
|
return menu;
|
|
/*START*/
|
|
}
|
|
|
|
/*
|
|
this function returns the checked state of a checkable menu item.
|
|
*/
|
|
BOOLEAN
|
|
XinWindowMenuItemIsChecked( XinWindow win, XinMenuTag tag )
|
|
{
|
|
/*END*/
|
|
BOOLEAN checked;
|
|
XinMenuItem *item = XinWindowMenuItemGet( win, tag );
|
|
|
|
if ( item == 0 )
|
|
return FALSE;
|
|
checked = item->checked;
|
|
XinMenuItemFree( item );
|
|
return checked;
|
|
/*START*/
|
|
}
|
|
|
|
/*
|
|
this function returns the enabled state of a menu item.
|
|
*/
|
|
BOOLEAN
|
|
XinWindowMenuItemIsEnabled( XinWindow win, XinMenuTag tag )
|
|
{
|
|
/*END*/
|
|
BOOLEAN enabled;
|
|
XinMenuItem *item = XinWindowMenuItemGet( win, tag );
|
|
|
|
if ( item == 0 )
|
|
return FALSE;
|
|
enabled = item->enabled;
|
|
XinMenuItemFree( item );
|
|
return enabled;
|
|
/*START*/
|
|
}
|
|
|
|
/*
|
|
this function replaces a single menu item with the specified tag.
|
|
*/
|
|
void
|
|
XinWindowMenuItemReplace( XinWindow win, XinMenuTag tag, XinMenuItem * item )
|
|
{
|
|
/*END*/
|
|
MENU_ITEM *old_item;
|
|
MENU_ITEM *tree = xvt_menu_get_tree( ( WINDOW ) win );
|
|
|
|
old_item = find_item( tree, tag );
|
|
if ( item != NULL )
|
|
{
|
|
copy_item_to_xvt( old_item, item );
|
|
}
|
|
xvt_res_free_menu_tree( tree );
|
|
/*START*/
|
|
}
|
|
|
|
/*
|
|
this function retrieves a menu item. it allocates the XinMenuItem. the
|
|
allocated XinMenuItem should be placed in a menu tree, or else explicitely
|
|
freed, otherwise, a memory leak will occur.
|
|
*/
|
|
XinMenuItem *
|
|
XinWindowMenuItemGet( XinWindow win, XinMenuTag tag )
|
|
{
|
|
/*END*/
|
|
MENU_ITEM *item;
|
|
XinMenuItem *new_item;
|
|
MENU_ITEM *tree = xvt_menu_get_tree( ( WINDOW ) win );
|
|
|
|
item = find_item( tree, tag );
|
|
if ( item == NULL )
|
|
new_item = NULL;
|
|
else
|
|
{
|
|
new_item = XinMemoryAlloc( sizeof( XinMenuItem ) );
|
|
copy_menu_item( new_item, item );
|
|
}
|
|
xvt_res_free_menu_tree( tree );
|
|
return new_item;
|
|
/*START*/
|
|
}
|
|
|
|
/*
|
|
this function replaces an existing menu tree with the specified menu tree.
|
|
if tag == 0, then this function replaces the entire menu tree for the window.
|
|
if tag != 0, then this function replaces just the branch of the tree, starting
|
|
at the menu item with the specified tag.
|
|
*/
|
|
void
|
|
XinWindowMenuReplace( XinWindow win, XinMenuTag tag, XinMenu * menu )
|
|
{
|
|
/*END*/
|
|
MENU_ITEM *item;
|
|
MENU_ITEM *tree;
|
|
|
|
if ( tag == 0 )
|
|
{
|
|
tree = make_xvt_menu( menu->nbr_items, menu->items );
|
|
if ( tree == NULL )
|
|
return;
|
|
xvt_menu_set_tree( ( WINDOW ) win, tree );
|
|
}
|
|
else
|
|
{
|
|
tree = xvt_menu_get_tree( ( WINDOW ) win );
|
|
item = find_item( tree, tag );
|
|
if ( item != NULL )
|
|
{
|
|
if ( item->child != NULL )
|
|
xvt_res_free_menu_tree( item->child );
|
|
if ( menu->nbr_items == 0 )
|
|
item->child = NULL;
|
|
else
|
|
item->child = make_xvt_menu( menu->nbr_items, menu->items );
|
|
xvt_menu_set_tree( ( WINDOW ) win, tree );
|
|
}
|
|
}
|
|
if ( tree != NULL )
|
|
xvt_res_free_menu_tree( tree );
|
|
/*START*/
|
|
}
|
|
|
|
/*
|
|
gets the text of the specified menu item.
|
|
*/
|
|
char *
|
|
XinWindowMenuItemTextGet( XinWindow win, XinMenuTag tag )
|
|
{
|
|
/*END*/
|
|
XinMenuItem *item = XinWindowMenuItemGet( win, tag );
|
|
|
|
XinInitBuffer( );
|
|
if ( item == 0 )
|
|
return NULL;
|
|
if ( item->text == NULL )
|
|
xin_buffer[0] = '\0';
|
|
else
|
|
strcpy( xin_buffer, item->text );
|
|
XinMenuItemFree( item );
|
|
return xin_buffer;
|
|
/*START*/
|
|
}
|
|
|
|
/*
|
|
sets the text of the specified menu item.
|
|
*/
|
|
void
|
|
XinWindowMenuItemTextSet( XinWindow win, XinMenuTag tag, char *text )
|
|
{
|
|
/*END*/
|
|
xvt_menu_set_item_title( ( WINDOW ) win, ( MENU_TAG ) tag, text );
|
|
/*START*/
|
|
}
|
|
|
|
/*
|
|
this function traps the mouse to the specified window. see the discussion
|
|
above on mouse trapping. the argument 'continuous_mouse_moves' should be
|
|
implemented if not difficult to do.
|
|
*/
|
|
void
|
|
XinWindowMouseTrap( XinWindow win, BOOLEAN continuous_mouse_moves )
|
|
{
|
|
/*END*/
|
|
/* This is only handled under Motif. */
|
|
NOREF( continuous_mouse_moves );
|
|
|
|
xvt_win_trap_pointer( ( WINDOW ) win );
|
|
/*START*/
|
|
}
|
|
|
|
/*
|
|
this function releases a previously trapped mouse.
|
|
*/
|
|
void
|
|
XinWindowMouseRelease( void )
|
|
{
|
|
/*END*/
|
|
xvt_win_release_pointer( );
|
|
/*START*/
|
|
}
|
|
|
|
/*
|
|
under the MFC port, this function will return the MFC object for the window.
|
|
this facilitates the module using Xin to write code that uses MFC directly if
|
|
necessary.
|
|
*/
|
|
long
|
|
XinWindowNativeGet( XinWindow win )
|
|
{
|
|
/*END*/
|
|
return xvt_vobj_get_attr( ( WINDOW ) win, ATTR_NATIVE_WINDOW );
|
|
/*START*/
|
|
}
|
|
|
|
/*
|
|
this function forces all pending paint events to be generated. if certain
|
|
regions have been invalidated, and the module using Xin does not know that
|
|
all invalidated regions have received their respective paint events, then
|
|
the user of Xin can call this function. this is often done before calling
|
|
a scroll rectangular region function, because the scroll rectangular region
|
|
function uses the actual pixels in the window as the input for the bitblt.
|
|
*/
|
|
void
|
|
XinWindowPaintForce( XinWindow Win )
|
|
{
|
|
/*END*/
|
|
xvt_dwin_update( ( WINDOW ) Win );
|
|
/*START*/
|
|
}
|
|
|
|
/*
|
|
when the user of Xin is processing an XinEventPaint, then it can call this
|
|
function to determine if a particular rectangle needs to be drawn.
|
|
*/
|
|
BOOLEAN
|
|
XinWindowPaintNeeds( XinWindow Win, XinRect * rctp )
|
|
{
|
|
/*END*/
|
|
return xvt_dwin_is_update_needed( ( WINDOW ) Win, ( RCT * ) rctp );
|
|
/*START*/
|
|
}
|
|
|
|
/*
|
|
this function returns the parent of the specified window. for all top level
|
|
windows, the parent window is the task window. for scroll bars, the parent
|
|
window is the window that contains the scroll bar. Xin does not implement
|
|
child windows of top level windows.
|
|
*/
|
|
XinWindow
|
|
XinWindowParentGet( XinWindow Win )
|
|
{
|
|
/*END*/
|
|
return ( XinWindow ) xvt_vobj_get_parent( ( WINDOW ) Win );
|
|
/*START*/
|
|
}
|
|
|
|
/*
|
|
this function sets the current pen for drawing lines. calls to XinWindowPenGet
|
|
and XinWindowDrawToolsGet will reflect the changes made through this call.
|
|
*/
|
|
void
|
|
XinWindowPenSet( XinWindow win, XinPen * Pen )
|
|
{
|
|
/*END*/
|
|
CPEN cpen;
|
|
|
|
cpen.color = Pen->fore_color;
|
|
cpen.pat = PenPatternToPAT( Pen->pattern );
|
|
cpen.width = Pen->width;
|
|
switch ( Pen->pattern )
|
|
{
|
|
case XinPenDashed:
|
|
cpen.style = P_DASH;
|
|
break;
|
|
case XinPenDotted:
|
|
cpen.style = P_DOT;
|
|
break;
|
|
default:
|
|
cpen.style = P_SOLID;
|
|
break;
|
|
}
|
|
#if XIWS == XIWS_WM
|
|
xi_fix_color( &cpen.color );
|
|
#endif
|
|
xvt_dwin_set_cpen( ( WINDOW ) win, &cpen );
|
|
/*START*/
|
|
}
|
|
|
|
/*
|
|
this function draws a pie in the specified window, following the state of
|
|
clipping, pens, brushes, and copy mode. see the drawing discussion above for
|
|
more details.
|
|
*/
|
|
void
|
|
XinWindowPieDraw( XinWindow Win, XinRect* rctp, XinPoint* start, XinPoint* stop )
|
|
{
|
|
/*END*/
|
|
RCT r;
|
|
|
|
r.left = rctp->left;
|
|
r.top = rctp->top;
|
|
r.right = rctp->right;
|
|
r.bottom = rctp->bottom;
|
|
xvt_dwin_draw_pie( ( WINDOW ) Win, &r, start->h, start->v, stop->h, stop->v );
|
|
/*START*/
|
|
}
|
|
|
|
/*
|
|
This function is used to translate points from one window coordinate system to
|
|
another. It does not have to work for scrollbars. The coordinate system of a
|
|
window is 0,0 in the upper-left corner of the client rectangle. The screen window
|
|
is 0,0 in the upper-left corner of the display.
|
|
*/
|
|
void
|
|
XinWindowPointsTranslate( XinWindow FromWin, XinWindow ToWin, XinPoint * Pnts, int NbrPnts )
|
|
{
|
|
/*END*/
|
|
xvt_vobj_translate_points( ( WINDOW ) FromWin, ( WINDOW ) ToWin, ( PNT * ) Pnts, NbrPnts );
|
|
/*START*/
|
|
}
|
|
|
|
/*
|
|
this function draws a polygon in the specified window, following the state of
|
|
clipping, pens, brushes, and copy mode. see the drawing discussion above for
|
|
more details.
|
|
*/
|
|
void
|
|
XinWindowPolygonDraw( XinWindow Win, XinPoint* points, int nbr_points )
|
|
{
|
|
/*END*/
|
|
xvt_dwin_draw_polygon( ( WINDOW ) Win, (PNT*)points, nbr_points );
|
|
/*START*/
|
|
}
|
|
|
|
/*
|
|
this function draws a rectangle in the specified window, following the state of
|
|
clipping, pens, brushes, and copy mode. see the drawing discussion above for
|
|
more details.
|
|
*/
|
|
void
|
|
XinWindowRectDraw( XinWindow Win, XinRect * rctp )
|
|
{
|
|
/*END*/
|
|
RCT r;
|
|
|
|
r.left = rctp->left;
|
|
r.top = rctp->top;
|
|
r.right = rctp->right;
|
|
r.bottom = rctp->bottom;
|
|
/* Hack for OS2 - rectangles won't draw if right or bottom equal
|
|
to SHRT_MAX 8/96 XVT 4.02 */
|
|
#if XIWS == XIWS_PM
|
|
if ( r.right == SHRT_MAX )
|
|
r.right = 9999;
|
|
if ( r.bottom == SHRT_MAX )
|
|
r.bottom = 9999;
|
|
#endif
|
|
xvt_dwin_draw_rect( ( WINDOW ) Win, &r );
|
|
/*START*/
|
|
}
|
|
|
|
/*
|
|
this function draws a dotted rectangle in the specified window (added by Guy).
|
|
*/
|
|
void
|
|
XinWindowRoundRectDraw( XinWindow Win, XinRect * rctp, int rh, int rv )
|
|
{
|
|
/*END*/
|
|
RCT r;
|
|
r.left = rctp->left;
|
|
r.top = rctp->top;
|
|
r.right = rctp->right;
|
|
r.bottom = rctp->bottom;
|
|
xvt_dwin_draw_roundrect(( WINDOW ) Win, &r, rh, rv );
|
|
/*START*/
|
|
}
|
|
|
|
|
|
/*
|
|
this function draws a dotted rectangle in the specified window (added by Guy).
|
|
*/
|
|
void
|
|
XinWindowDottedRectDraw( XinWindow Win, XinRect * rctp )
|
|
{
|
|
/*END*/
|
|
RCT r;
|
|
r.left = rctp->left;
|
|
r.top = rctp->top;
|
|
r.right = rctp->right;
|
|
r.bottom = rctp->bottom;
|
|
xvt_dwin_draw_dotted_rect( ( WINDOW ) Win, &r );
|
|
/*START*/
|
|
}
|
|
|
|
|
|
/*
|
|
this function fills in the rectangle passed in as a pointer 'Rctp' with the
|
|
coordinates of the client area of the specified window. The top and left
|
|
will always be 0. This function can be called for the screen window to
|
|
get the display size.
|
|
*/
|
|
XinRect *
|
|
XinWindowRectGet( XinWindow Win, XinRect * Rctp )
|
|
{
|
|
/*END*/
|
|
RCT r;
|
|
|
|
xvt_vobj_get_client_rect( ( WINDOW ) Win, &r );
|
|
Rctp->top = r.top;
|
|
Rctp->left = r.left;
|
|
Rctp->bottom = r.bottom;
|
|
Rctp->right = r.right;
|
|
return Rctp;
|
|
/*START*/
|
|
}
|
|
|
|
/*
|
|
this function introduces a paint event into the event queue. the area for which
|
|
a paint event will be generated is specified in the argument 'rctp'.
|
|
*/
|
|
void
|
|
XinWindowRectInvalidate( XinWindow win, XinRect * rctp )
|
|
{
|
|
/*END*/
|
|
RCT r;
|
|
|
|
if ( rctp == NULL )
|
|
{
|
|
xvt_dwin_invalidate_rect( ( WINDOW ) win, NULL );
|
|
#ifdef COALESCE_UPDATES
|
|
{
|
|
WindowInfo *info = find_window_info( ( WINDOW ) win );
|
|
|
|
if ( info != NULL && info->coalesce.coalescing != 0 )
|
|
info->coalesce.invalidated = FALSE;
|
|
}
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
r.left = rctp->left;
|
|
r.top = rctp->top;
|
|
r.right = rctp->right;
|
|
r.bottom = rctp->bottom;
|
|
#ifdef COALESCE_UPDATES
|
|
{
|
|
WindowInfo *info = find_window_info( ( WINDOW ) win );
|
|
|
|
if ( info != NULL && info->coalesce.coalescing != 0 )
|
|
{
|
|
if ( info->coalesce.invalidated )
|
|
XinRectEnclose( &info->coalesce.inv_rct, &info->coalesce.inv_rct,
|
|
rctp );
|
|
else
|
|
info->coalesce.inv_rct = *rctp;
|
|
info->coalesce.invalidated = TRUE;
|
|
}
|
|
else
|
|
xvt_dwin_invalidate_rect( ( WINDOW ) win, &r );
|
|
}
|
|
#else
|
|
xvt_dwin_invalidate_rect( ( WINDOW ) win, &r );
|
|
#endif
|
|
/*START*/
|
|
}
|
|
|
|
/*
|
|
this function gets the rectangle of a window, including the border of the window.
|
|
The top and left values will reflect the windows position within its parent.
|
|
This function can be called for the screen window to get the display size.
|
|
*/
|
|
XinRect *
|
|
XinWindowRectOuterGet( XinWindow Win, XinRect * Rctp )
|
|
{
|
|
/*END*/
|
|
RCT r;
|
|
|
|
xvt_vobj_get_outer_rect( ( WINDOW ) Win, &r );
|
|
Rctp->top = r.top;
|
|
Rctp->left = r.left;
|
|
Rctp->bottom = r.bottom;
|
|
Rctp->right = r.right;
|
|
return Rctp;
|
|
/*START*/
|
|
}
|
|
|
|
/*
|
|
this function causes a rectangular region to be scrolled in a horizontal direction,
|
|
a vertical direction, or both. the window system will do a bitblt to move the pixels,
|
|
and invalidate the exposed region. only pixels inside the rectangle 'Rctp' are
|
|
affected. no pixels outside of the rectangle are affected. The clipping rectangle
|
|
should not affect this function.
|
|
|
|
the paint event for the exposed region must come through recursively.
|
|
*/
|
|
void
|
|
XinWindowRectScroll( XinWindow Win, XinRect * Rctp, int dh, int dv )
|
|
{
|
|
/*END*/
|
|
#if XIWS == XIWS_WM
|
|
{ /* Strange bug in CH needs clipping region set
|
|
* twice. */
|
|
XinRect rct;
|
|
|
|
rct = *Rctp;
|
|
rct.bottom += 24;
|
|
XinWindowClipSet( Win, &rct );
|
|
XinWindowClipSet( Win, NULL );
|
|
}
|
|
#endif
|
|
#if XIWS == XIWS_PM
|
|
/* Hack for OS2 - headings don't scroll if clip rect is not set
|
|
8/96 XVT 4.02 */
|
|
XinWindowClipSet( Win, Rctp );
|
|
#endif
|
|
#if XIWS == XIWS_MAC
|
|
XinWindowClipSet( Win, NULL );
|
|
#endif
|
|
xvt_dwin_scroll_rect( ( WINDOW ) Win, ( RCT * ) Rctp, dh, dv );
|
|
/*START*/
|
|
}
|
|
|
|
/*
|
|
this function changes the size and/or position of the window as
|
|
specified by the rectangle, which specifies the outer rectangle.
|
|
*/
|
|
void
|
|
XinWindowRectSet( XinWindow Win, XinRect * Rctp )
|
|
{
|
|
/*END*/
|
|
xvt_vobj_move( ( WINDOW ) Win, ( RCT * ) Rctp );
|
|
/*START*/
|
|
}
|
|
|
|
/*
|
|
this function has the identical functionality to XinWindowPointsTranslate, except
|
|
that it translates a rectangle instead of points.
|
|
*/
|
|
void
|
|
XinWindowRectTranslate( XinWindow FromWin, XinWindow ToWin, XinRect * rect )
|
|
{
|
|
/*END*/
|
|
xvt_vobj_translate_points( ( WINDOW ) FromWin, ( WINDOW ) ToWin, ( PNT * ) rect, 2 );
|
|
/*START*/
|
|
}
|
|
|
|
/*
|
|
this function returns the screen window to the module using Xin.
|
|
*/
|
|
XinWindow
|
|
XinWindowScreenGet( void )
|
|
{
|
|
/*END*/
|
|
return ( XinWindow ) SCREEN_WIN;
|
|
/*START*/
|
|
}
|
|
|
|
/*
|
|
this function makes a window visible or invisible.
|
|
*/
|
|
void
|
|
XinWindowShow( XinWindow Win, BOOLEAN Show )
|
|
{
|
|
/*END*/
|
|
xvt_vobj_set_visible( ( WINDOW ) Win, Show );
|
|
/*START*/
|
|
}
|
|
|
|
/*
|
|
this function returns the task window to the module using Xin.
|
|
*/
|
|
XinWindow
|
|
XinWindowTaskGet( void )
|
|
{
|
|
/*END*/
|
|
return ( XinWindow ) TASK_WIN;
|
|
/*START*/
|
|
}
|
|
|
|
/*END*/
|
|
BOOLEAN xin_use_mdi_flag = TRUE; /* This is set in xiport2.c */
|
|
/*START*/
|
|
|
|
/*
|
|
this function returns the window that is most appropriate to be
|
|
a drop-down-position window's parent.
|
|
*/
|
|
XinWindow
|
|
XinWindowDropDownParentGet( XinWindow creating_win )
|
|
{
|
|
/*END*/
|
|
#if XIWS == XIWS_WIN
|
|
#if 0
|
|
if ( creating_win == xin_modal_win || xin_use_mdi_flag )
|
|
return ( XinWindow ) SCREEN_WIN; /* Unless creating_win is modal, this
|
|
will have a title bar. Life sucks. */
|
|
return ( XinWindow ) TASK_WIN;
|
|
#endif
|
|
return ( XinWindow ) SCREEN_WIN;
|
|
#else
|
|
return ( XinWindow ) TASK_WIN;
|
|
#endif
|
|
/*START*/
|
|
}
|
|
|
|
/*
|
|
this function sets or resets the opaque drawing mode for text drawing.
|
|
*/
|
|
void
|
|
XinWindowTextOpaqueSet( XinWindow win, BOOLEAN opaque )
|
|
{
|
|
/*END*/
|
|
DRAW_CTOOLS ct;
|
|
|
|
xvt_dwin_get_draw_ctools( ( WINDOW ) win, &ct );
|
|
ct.opaque_text = opaque;
|
|
xvt_dwin_set_draw_ctools( ( WINDOW ) win, &ct );
|
|
/*START*/
|
|
}
|
|
|
|
/*
|
|
this function draws text in the specified window, using the specified font,
|
|
at the specified position. it uses the current fore_color, and back_color
|
|
if drawing in opaque mode. it obeys the current clipping region.
|
|
*/
|
|
void
|
|
XinWindowTextDraw( XinWindow Win, XinFont * font, int x, int y,
|
|
char *buf, int len )
|
|
{
|
|
/*END*/
|
|
xvt_dwin_set_font( ( WINDOW ) Win, font->xvt_fntid );
|
|
xvt_dwin_draw_text( ( WINDOW ) Win, x, y, buf, len );
|
|
/*START*/
|
|
}
|
|
|
|
/*
|
|
this function draws text in the specified window, using the specified font,
|
|
at the specified position and rotated by the specified amount.
|
|
it uses the current fore_color, and back_color if drawing in opaque mode.
|
|
it obeys the current clipping region.
|
|
*/
|
|
void
|
|
XinWindowTextRotateDraw( XinWindow Win, XinFont * font, int x, int y,
|
|
int rotation, char *buf, int len )
|
|
{
|
|
/*END*/
|
|
XinRect rect;
|
|
int leading, ascent, descent, height;
|
|
int num;
|
|
|
|
if ( rotation == 0 )
|
|
{
|
|
XinWindowTextDraw( Win, font, x, y, buf, len );
|
|
return;
|
|
} else if ( rotation != 90 && rotation != 270 )
|
|
return;
|
|
|
|
xvt_dwin_set_font( (WINDOW)Win, font->xvt_fntid );
|
|
xvt_font_map( font->xvt_fntid, (WINDOW)Win );
|
|
xvt_font_get_metrics( font->xvt_fntid, &leading, &ascent, &descent );
|
|
height = leading + ascent + descent;
|
|
if ( len == -1 )
|
|
len = strlen( buf );
|
|
if ( rotation == 90 )
|
|
{
|
|
rect.top = y;
|
|
rect.bottom = y + len * height;
|
|
rect.left = x - ( ascent + leading );
|
|
rect.right = x + descent;
|
|
} else
|
|
{
|
|
rect.top = y - len * height;
|
|
rect.bottom = y;
|
|
rect.left = x - descent;
|
|
rect.right = x + ascent + leading;
|
|
}
|
|
y = rect.top + leading + ascent;
|
|
for ( num = 0; num < len; num++, y += height, buf++ )
|
|
{
|
|
int width = xvt_dwin_get_text_width( (WINDOW)Win, buf, 1 );
|
|
if ( width < height )
|
|
x = rect.left + ( height - width ) / 2;
|
|
else
|
|
x = rect.left;
|
|
xvt_dwin_draw_text( (WINDOW)Win, x, y, buf, 1 );
|
|
}
|
|
xvt_dwin_draw_text( ( WINDOW ) Win, x, y, buf, len );
|
|
/*START*/
|
|
}
|
|
|
|
/*
|
|
this function kills a timer identified by 'Timer_id'.
|
|
*/
|
|
void
|
|
XinWindowTimerKill( XinWindow win, long Timer_id )
|
|
{
|
|
/*END*/
|
|
NOREF( win );
|
|
xvt_timer_destroy( Timer_id );
|
|
/*START*/
|
|
}
|
|
|
|
/*
|
|
this function creates a timer that will generate events a specified number of
|
|
milliseconds apart.
|
|
*/
|
|
long
|
|
XinWindowTimerSet( XinWindow Win, long Millisecs )
|
|
{
|
|
/*END*/
|
|
return xvt_timer_create( ( WINDOW ) Win, Millisecs );
|
|
/*START*/
|
|
}
|
|
|
|
/*
|
|
this function returns the title of the specified window.
|
|
*/
|
|
char *
|
|
XinWindowTitleGet( XinWindow Win )
|
|
{
|
|
/*END*/
|
|
static char title[250];
|
|
|
|
if ( xvt_vobj_get_title( ( WINDOW ) Win, title, sizeof( title ) ) == NULL )
|
|
title[0] = '\0';
|
|
return title;
|
|
/*START*/
|
|
}
|
|
|
|
/*
|
|
this function sets the title of the specified window.
|
|
*/
|
|
void
|
|
XinWindowTitleSet( XinWindow Win, char *Title )
|
|
{
|
|
/*END*/
|
|
xvt_vobj_set_title( ( WINDOW ) Win, Title );
|
|
/*START*/
|
|
}
|
|
|
|
/*END*/
|
|
static SCROLL_TYPE
|
|
convert_to_SCROLL_TYPE( XinScrollBarType type )
|
|
{
|
|
switch ( type )
|
|
{
|
|
case XinScrollBarTypeHorizontal:
|
|
return HSCROLL;
|
|
case XinScrollBarTypeVertical:
|
|
return VSCROLL;
|
|
case XinScrollBarTypeEither:
|
|
return HVSCROLL;
|
|
}
|
|
return HSCROLL;
|
|
}
|
|
|
|
/*
|
|
this function gets the current position of the scroll bar specified by
|
|
the argument 'Win'.
|
|
*/
|
|
int
|
|
XinScrollBarPositionGet( XinWindow Win, XinScrollBarType Type )
|
|
{
|
|
return xvt_sbar_get_pos( ( WINDOW ) Win, convert_to_SCROLL_TYPE( Type ) );
|
|
}
|
|
|
|
/*
|
|
this function sets the current position of the scroll bar specified by
|
|
the argument 'Win'.
|
|
*/
|
|
void
|
|
XinScrollBarPositionSet( XinWindow Win, XinScrollBarType Type, int Top )
|
|
{
|
|
if ( app_terminating )
|
|
return;
|
|
xvt_sbar_set_pos( ( WINDOW ) Win, convert_to_SCROLL_TYPE( Type ), Top );
|
|
}
|
|
|
|
/*
|
|
this function gets the current proportion for a scrollbar
|
|
*/
|
|
int
|
|
XinScrollBarProportionGet( XinWindow Win, XinScrollBarType Type )
|
|
{
|
|
return xvt_sbar_get_proportion( ( WINDOW ) Win, convert_to_SCROLL_TYPE( Type ) );
|
|
}
|
|
|
|
/*
|
|
this function gets the current range for a scrollbar
|
|
*/
|
|
void
|
|
XinScrollBarRangeGet( XinWindow Win, XinScrollBarType Type, int *Rng1, int *Rng2 )
|
|
{
|
|
if ( app_terminating )
|
|
return;
|
|
xvt_sbar_get_range( ( WINDOW ) Win, convert_to_SCROLL_TYPE( Type ), Rng1, Rng2 );
|
|
}
|
|
|
|
/*
|
|
this function sets the range (min_val, max_val), proportion, and position for
|
|
a scrollbar
|
|
*/
|
|
void
|
|
XinScrollBarSet( XinWindow Win, XinScrollBarType Type, int min_val, int max_val,
|
|
int proportion, int pos )
|
|
{
|
|
WINDOW xvt_win = ( WINDOW ) Win;
|
|
SCROLL_TYPE scroll_type = convert_to_SCROLL_TYPE( Type );
|
|
|
|
#if XIWS == XIWS_XM
|
|
WINDOW parent_win = xvt_vobj_get_parent( xvt_win );
|
|
|
|
if ( proportion != 0 )
|
|
{
|
|
if ( pos == min_val )
|
|
pos = min_val + 1;
|
|
if ( pos == ( max_val - proportion ) )
|
|
pos = max_val - proportion - 1;
|
|
#endif
|
|
xvt_sbar_set_range( xvt_win, scroll_type, min_val, max_val );
|
|
xvt_sbar_set_proportion( xvt_win, scroll_type, proportion );
|
|
#if XIWS == XIWS_WXGTK
|
|
if (pos >= 0)
|
|
#endif
|
|
xvt_sbar_set_pos( xvt_win, scroll_type, pos );
|
|
#if XIWS == XIWS_XM
|
|
{
|
|
WINDOW focus_win = xvt_scr_get_focus_vobj();
|
|
if ( parent_win && (focus_win == xvt_win) )
|
|
xvt_scr_set_focus_vobj( parent_win );
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
this function queries whether a particular format is available on the clipboard.
|
|
*/
|
|
BOOLEAN
|
|
XinClipboardFormatAvail( XinClipboardFormat Format )
|
|
{
|
|
/*END*/
|
|
switch ( Format )
|
|
{
|
|
case XinClipboardFormatText:
|
|
return xvt_cb_has_format( CB_TEXT, NULL );
|
|
case XinClipboardFormatBitmap:
|
|
return FALSE;
|
|
}
|
|
return FALSE;
|
|
/*START*/
|
|
}
|
|
|
|
/*
|
|
given a format, this function gets the contents of the clipboard.
|
|
*/
|
|
void *
|
|
XinClipboardGet( XinClipboardFormat Format, long *size )
|
|
{
|
|
/*END*/
|
|
char *ptr = NULL;
|
|
|
|
if ( !xvt_cb_open( FALSE ) )
|
|
return ptr;
|
|
switch ( Format )
|
|
{
|
|
case XinClipboardFormatText:
|
|
{
|
|
void *cb_ptr;
|
|
|
|
cb_ptr = xvt_cb_get_data( CB_TEXT, NULL, size );
|
|
if ( cb_ptr != NULL && *size > 0 )
|
|
{
|
|
ptr = XinMemoryAlloc( ( int ) ( *size + 1 ) );
|
|
memcpy( ptr, cb_ptr, ( int ) *size );
|
|
ptr[( int ) *size] = '\0';
|
|
}
|
|
break;
|
|
}
|
|
case XinClipboardFormatBitmap:
|
|
ptr = NULL;
|
|
break;
|
|
}
|
|
xvt_cb_close( );
|
|
return ptr;
|
|
/*START*/
|
|
}
|
|
|
|
/*
|
|
this function puts data on to the clipboard. the format of the
|
|
data is specified in the argument 'format'.
|
|
*/
|
|
void
|
|
XinClipboardPut( XinClipboardFormat format, long size, void *data )
|
|
{
|
|
/*END*/
|
|
CB_FORMAT xvt_format;
|
|
char *buf;
|
|
|
|
if ( !xvt_cb_open( TRUE ) )
|
|
return;
|
|
buf = xvt_cb_alloc_data( size + 1 );
|
|
memcpy( buf, data, ( size_t ) size );
|
|
buf[( int ) size] = '\0';
|
|
switch ( format )
|
|
{
|
|
case XinClipboardFormatText:
|
|
xvt_format = CB_TEXT;
|
|
buf = NULL;
|
|
break;
|
|
case XinClipboardFormatBitmap:
|
|
xvt_format = CB_PICT;
|
|
break;
|
|
default:
|
|
xvt_format = CB_APPL;
|
|
break;
|
|
}
|
|
xvt_cb_put_data( xvt_format, NULL, size + 1, ( PICTURE ) buf );
|
|
xvt_cb_free_data( );
|
|
xvt_cb_close( );
|
|
/*START*/
|
|
}
|
|
|
|
/*END*/
|
|
void
|
|
xi_terminate( void )
|
|
{
|
|
app_terminating = TRUE;
|
|
xvt_vobj_destroy( TASK_WIN );
|
|
}
|
|
|
|
/*START*/
|
|
/*
|
|
when the application is terminated, it generates an XinEventQuit event.
|
|
during the XinEventQuit, the application can put up a dialog box if desired,
|
|
querying from the user whether it is ok to quit the application, and
|
|
possibly saving files. if it is ok for the application to quit, then
|
|
during processing of that event, the module using Xin should call
|
|
XinAppQuitOk.
|
|
*/
|
|
void
|
|
XinAppQuitOk( void )
|
|
{
|
|
/*END*/
|
|
xvt_app_allow_quit( );
|
|
/*START*/
|
|
}
|
|
|
|
/*
|
|
this function terminates the application. it will cause an XinEventQuit
|
|
event to be generated. see XinAppQuitOk for more details.
|
|
*/
|
|
void
|
|
XinAppTerminate( void )
|
|
{
|
|
/*END*/
|
|
XinMemoryFree( xin_buffer );
|
|
if (xin_family_names_initialized)
|
|
{
|
|
XinMemoryFree( xin_family_name_times );
|
|
XinMemoryFree( xin_family_name_fixed );
|
|
XinMemoryFree( xin_family_name_system );
|
|
XinMemoryFree( xin_family_name_helvetica );
|
|
}
|
|
app_terminating = TRUE;
|
|
xvt_vobj_destroy( TASK_WIN );
|
|
/*START*/
|
|
}
|
|
|
|
/*
|
|
this function prints to a file named "DEBUG". if the file does not exist,
|
|
then this function does nothing. if the file exists, then the first time
|
|
that this function is called, it creates the debug file over top of the
|
|
existing one. thereafter, this function appends to the debug file.
|
|
The data written to the file must be flushed at the end of the function,
|
|
perhaps by closing the file.
|
|
*/
|
|
void
|
|
XinDebugPrintf( char *format,... )
|
|
{
|
|
/*END*/
|
|
va_list argptr;
|
|
|
|
XinInitBuffer( );
|
|
va_start( argptr, format );
|
|
vsprintf( xin_buffer, format, argptr );
|
|
va_end( argptr );
|
|
xvt_debug_printf( "%s", xin_buffer );
|
|
/*START*/
|
|
}
|
|
|
|
/*
|
|
this function forces any pending events to be sent to the application.
|
|
it typically is called during processing that will take more than one
|
|
or two seconds.
|
|
*/
|
|
void
|
|
XinPendingEventsProcess( void )
|
|
{
|
|
/*END*/
|
|
xvt_app_process_pending_events( );
|
|
/*START*/
|
|
}
|
|
|
|
/*
|
|
this function makes a small noise.
|
|
*/
|
|
void
|
|
XinBeep( void )
|
|
{
|
|
/*END*/
|
|
xvt_scr_beep( );
|
|
/*START*/
|
|
}
|
|
|
|
/*
|
|
this function takes separate red, green, and blue values and creates
|
|
one RGB value.
|
|
|
|
the following implementation is complete.
|
|
*/
|
|
XinColor
|
|
XinColorMake( int red, int green, int blue )
|
|
{
|
|
return ( red << 16 ) | ( green << 8 ) | blue;
|
|
}
|
|
|
|
/*
|
|
this function compares a string to a pattern. the pattern can contain
|
|
wild cards (*, ?) returns TRUE if the pattern matches the string.
|
|
if 'case_sensitive' is true, then this function pays attention to the
|
|
case of the characters.
|
|
*/
|
|
BOOLEAN
|
|
XinStringMatch( char *string, char *pattern, BOOLEAN case_sensitive )
|
|
{
|
|
/*END*/
|
|
return xvt_str_match( string, pattern, case_sensitive );
|
|
/*START*/
|
|
}
|
|
|
|
/*
|
|
this function changes the cursor to the wait cursor until the program
|
|
returns from processing the event during which this function was called.
|
|
*/
|
|
void
|
|
XinCursorWait( )
|
|
{
|
|
/*END*/
|
|
xvt_scr_set_busy_cursor( );
|
|
/*START*/
|
|
}
|
|
|
|
/*
|
|
this function gets metrics of many things in the GUI.
|
|
*/
|
|
long
|
|
XinMetricGet( XinMetricType type )
|
|
{
|
|
switch ( type )
|
|
{
|
|
case XinMetricIconHeight:
|
|
return xvt_vobj_get_attr( NULL_WIN, ATTR_ICON_HEIGHT );
|
|
case XinMetricIconWidth:
|
|
return xvt_vobj_get_attr( NULL_WIN, ATTR_ICON_WIDTH );
|
|
case XinMetricHorizontalScrollBarHeight:
|
|
return xvt_vobj_get_attr( NULL_WIN, ATTR_CTL_HORZ_SBAR_HEIGHT );
|
|
case XinMetricVerticalScrollBarWidth:
|
|
return xvt_vobj_get_attr( NULL_WIN, ATTR_CTL_VERT_SBAR_WIDTH );
|
|
case XinMetricScreenHeight:
|
|
return xvt_vobj_get_attr( NULL_WIN, ATTR_SCREEN_HEIGHT );
|
|
case XinMetricScreenWidth:
|
|
return xvt_vobj_get_attr( NULL_WIN, ATTR_SCREEN_WIDTH );
|
|
case XinMetricSizableFrameHeight:
|
|
return xvt_vobj_get_attr( NULL_WIN, ATTR_DOCFRAME_HEIGHT );
|
|
case XinMetricSizableFrameWidth:
|
|
return xvt_vobj_get_attr( NULL_WIN, ATTR_DOCFRAME_WIDTH );
|
|
case XinMetricDoubleFrameHeight:
|
|
return xvt_vobj_get_attr( NULL_WIN, ATTR_DBLFRAME_HEIGHT );
|
|
case XinMetricDoubleFrameWidth:
|
|
return xvt_vobj_get_attr( NULL_WIN, ATTR_DBLFRAME_WIDTH );
|
|
case XinMetricFrameHeight:
|
|
return xvt_vobj_get_attr( NULL_WIN, ATTR_FRAME_HEIGHT );
|
|
case XinMetricFrameWidth:
|
|
return xvt_vobj_get_attr( NULL_WIN, ATTR_FRAME_WIDTH );
|
|
case XinMetricMenuHeight:
|
|
return xvt_vobj_get_attr( NULL_WIN, ATTR_MENU_HEIGHT );
|
|
case XinMetricTitleHeight:
|
|
return xvt_vobj_get_attr( NULL_WIN, ATTR_TITLE_HEIGHT );
|
|
case XinMetricVerticalStagger:
|
|
return xvt_vobj_get_attr( NULL_WIN, ATTR_DOC_STAGGER_VERT );
|
|
case XinMetricHorizontalStagger:
|
|
return xvt_vobj_get_attr( NULL_WIN, ATTR_DOC_STAGGER_HORZ );
|
|
case XinMetricScreenHRes:
|
|
return xvt_vobj_get_attr( NULL_WIN, ATTR_SCREEN_HRES );
|
|
case XinMetricScreenVRes:
|
|
return xvt_vobj_get_attr( NULL_WIN, ATTR_SCREEN_VRES );
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
in some situations, we desire to coalesce invalidated regions. this is not
|
|
used for MFC.
|
|
*/
|
|
void
|
|
XinCoalesceInvalidates( XinWindow win, BOOLEAN coalesce )
|
|
{
|
|
/*END*/
|
|
#ifdef COALESCE_UPDATES
|
|
WindowInfo *info = find_window_info( ( WINDOW ) win );
|
|
|
|
if ( info != NULL )
|
|
{
|
|
if ( coalesce )
|
|
{
|
|
if ( info->coalesce.coalescing == 0 )
|
|
info->coalesce.invalidated = FALSE;
|
|
++info->coalesce.coalescing;
|
|
}
|
|
else
|
|
{
|
|
--info->coalesce.coalescing;
|
|
if ( info->coalesce.coalescing == 0 && info->coalesce.invalidated )
|
|
XinWindowRectInvalidate( win, &info->coalesce.inv_rct );
|
|
}
|
|
}
|
|
#else
|
|
NOREF( win );
|
|
NOREF( coalesce );
|
|
#endif
|
|
/*START*/
|
|
}
|
|
|
|
/*END*/
|
|
void
|
|
XinXvtEventGet( void *xvte )
|
|
{
|
|
*( EVENT * ) xvte = *cur_xvt_event;
|
|
}
|
|
|
|
#define UNDEFINED 1000
|
|
char *
|
|
XinXvtEventTextGet( void *xvte )
|
|
{
|
|
int num;
|
|
static struct
|
|
{
|
|
int type;
|
|
char *desc;
|
|
} xvt_event_text[] =
|
|
{
|
|
{
|
|
E_CREATE, "E_CREATE"
|
|
},
|
|
{
|
|
E_DESTROY, "E_DESTROY"
|
|
},
|
|
{
|
|
E_FOCUS, "E_FOCUS"
|
|
},
|
|
{
|
|
E_SIZE, "E_SIZE"
|
|
},
|
|
{
|
|
E_UPDATE, "E_UPDATE"
|
|
},
|
|
{
|
|
E_CLOSE, "E_CLOSE"
|
|
},
|
|
{
|
|
E_MOUSE_DOWN, "E_MOUSE_DOWN"
|
|
},
|
|
{
|
|
E_MOUSE_UP, "E_MOUSE_UP"
|
|
},
|
|
{
|
|
E_MOUSE_MOVE, "E_MOUSE_MOVE"
|
|
},
|
|
{
|
|
E_MOUSE_DBL, "E_MOUSE_DBL"
|
|
},
|
|
{
|
|
E_CHAR, "E_CHAR"
|
|
},
|
|
{
|
|
E_VSCROLL, "E_VSCROLL"
|
|
},
|
|
{
|
|
E_HSCROLL, "E_HSCROLL"
|
|
},
|
|
{
|
|
E_COMMAND, "E_COMMAND"
|
|
},
|
|
{
|
|
E_FONT, "E_FONT"
|
|
},
|
|
{
|
|
E_CONTROL, "E_CONTROL"
|
|
},
|
|
{
|
|
E_TIMER, "E_TIMER"
|
|
},
|
|
{
|
|
E_QUIT, "E_QUIT"
|
|
},
|
|
{
|
|
E_HELP, "E_HELP"
|
|
},
|
|
{
|
|
E_USER, "E_USER"
|
|
},
|
|
{
|
|
UNDEFINED, "Unknown XVT Event"
|
|
}
|
|
};
|
|
|
|
for ( num = 0; xvt_event_text[num].type != ( ( EVENT * ) xvte )->type &&
|
|
xvt_event_text[num].type != UNDEFINED; num++ )
|
|
;
|
|
return xvt_event_text[num].desc;
|
|
}
|
|
|
|
/*START*/
|
|
/*
|
|
this function returns whether a rectangle is empty or not.
|
|
|
|
the following implementation is complete.
|
|
*/
|
|
BOOLEAN
|
|
XinRectEmpty( XinRect * rect )
|
|
{
|
|
return ( rect->top >= rect->bottom && rect->left >= rect->right );
|
|
}
|
|
|
|
/*
|
|
this function determines the intersection between two mathmatical rectangles.
|
|
|
|
the following implementation is complete.
|
|
*/
|
|
XinRect *
|
|
XinRectIntersect( XinRect * result, XinRect * r1, XinRect * r2 )
|
|
{
|
|
XinRect rect;
|
|
|
|
rect = *r1;
|
|
if ( r2->top > rect.top )
|
|
rect.top = r2->top;
|
|
if ( r2->left > rect.left )
|
|
rect.left = r2->left;
|
|
if ( r2->bottom < rect.bottom )
|
|
rect.bottom = r2->bottom;
|
|
if ( r2->right < rect.right )
|
|
rect.right = r2->right;
|
|
if ( rect.bottom < rect.top || rect.right < rect.left )
|
|
{
|
|
rect.bottom = rect.top;
|
|
rect.right = rect.left;
|
|
}
|
|
*result = rect;
|
|
return result;
|
|
}
|
|
|
|
/*
|
|
this function determines whether the specified point is contained in the
|
|
specified rectangle.
|
|
|
|
the following implementation is complete.
|
|
*/
|
|
BOOLEAN
|
|
XinRectPointContained( XinRect * rect, XinPoint * point )
|
|
{
|
|
return ( point->h >= rect->left && point->h <= rect->right
|
|
&& point->v >= rect->top && point->v <= rect->bottom );
|
|
}
|
|
|
|
/*
|
|
get the enclosing rectangle of two other rectangles.
|
|
src1, src2 are the rects of interest.
|
|
dst is set to the enclosing rect and returned.
|
|
If is OK for dst to equal one of the sources.
|
|
|
|
the following implementation is complete.
|
|
*/
|
|
XinRect *
|
|
XinRectEnclose( XinRect * dst, XinRect * src1, XinRect * src2 )
|
|
{
|
|
XinRect rct;
|
|
|
|
rct.top = min( src1->top, src2->top );
|
|
rct.left = min( src1->left, src2->left );
|
|
rct.bottom = max( src1->bottom, src2->bottom );
|
|
rct.right = max( src1->right, src2->right );
|
|
*dst = rct;
|
|
return ( dst );
|
|
}
|
|
|
|
/*END*/
|
|
static void
|
|
menu_free_items( int nbr_items, XinMenuItem * items )
|
|
{
|
|
int num;
|
|
XinMenuItem *item;
|
|
|
|
for ( num = 0, item = items; num < nbr_items; num++, item++ )
|
|
{
|
|
if ( item->text != NULL )
|
|
XinMemoryFree( item->text );
|
|
if ( item->nbr_children != 0 )
|
|
{
|
|
menu_free_items( item->nbr_children, item->children );
|
|
XinMemoryFree( item->children );
|
|
}
|
|
}
|
|
}
|
|
|
|
static char *
|
|
copy_menu_text( char *text )
|
|
{
|
|
char *new_text;
|
|
int size = strlen( text ) + 1;
|
|
|
|
new_text = XinMemoryAlloc( size );
|
|
memcpy( new_text, text, size );
|
|
return new_text;
|
|
}
|
|
|
|
static XinMenuItem *
|
|
menu_clone_items( int nbr_items, XinMenuItem * items )
|
|
{
|
|
int num;
|
|
XinMenuItem *item;
|
|
XinMenuItem *new_items;
|
|
|
|
new_items = XinMemoryAlloc( nbr_items * sizeof( XinMenuItem ) );
|
|
memmove( new_items, items, nbr_items * sizeof( XinMenuItem ) );
|
|
for ( num = 0, item = new_items; num < nbr_items; num++, item++ )
|
|
{
|
|
if ( item->text != NULL )
|
|
item->text = copy_menu_text( item->text );
|
|
if ( item->nbr_children != 0 )
|
|
item->children = menu_clone_items( item->nbr_children, item->children );
|
|
}
|
|
return new_items;
|
|
}
|
|
|
|
/*START*/
|
|
/*
|
|
this function adds the specified menu item into a menu structure at the position
|
|
indicated by index. It does not change the menu for any window.
|
|
|
|
it returns a pointer to the newly created menu item.
|
|
*/
|
|
XinMenuItem *
|
|
XinMenuAdd( XinMenu * menu, int index, XinMenuItem * item )
|
|
{
|
|
/*END*/
|
|
if ( index < 0 || index > menu->nbr_items )
|
|
return NULL;
|
|
|
|
if ( menu->nbr_items == 0 )
|
|
{
|
|
menu->nbr_items = 1;
|
|
menu->items = XinMemoryAlloc( sizeof( XinMenuItem ) );
|
|
}
|
|
else
|
|
{
|
|
menu->nbr_items++;
|
|
menu->items = XinMemoryRealloc( menu->items, menu->nbr_items
|
|
* sizeof( XinMenuItem ) );
|
|
}
|
|
if ( index < menu->nbr_items - 1 )
|
|
memmove( menu->items + index + 1, menu->items + index,
|
|
( menu->nbr_items - index - 1 ) * sizeof( XinMenuItem ) );
|
|
memmove( menu->items + index, item, sizeof( XinMenuItem ) );
|
|
item = menu->items + index;
|
|
if ( item->text != NULL )
|
|
item->text = copy_menu_text( item->text );
|
|
if ( item->nbr_children != 0 )
|
|
item->children = menu_clone_items( item->nbr_children, item->children );
|
|
return item;
|
|
/*START*/
|
|
}
|
|
|
|
/*
|
|
this function creates an empty menu. subsequent to this, the module using Xin
|
|
will probably call XinMenuAdd.
|
|
|
|
the following implementation is complete.
|
|
*/
|
|
XinMenu *
|
|
XinMenuCreate( void )
|
|
{
|
|
XinMenu *menu = XinMemoryAlloc( sizeof( XinMenu ) );
|
|
|
|
menu->nbr_items = 0;
|
|
menu->items = NULL;
|
|
return menu;
|
|
}
|
|
|
|
/*
|
|
this function deletes a menu item at a specified index in a menu structure.
|
|
It does not change the menu for any window.
|
|
*/
|
|
BOOLEAN
|
|
XinMenuDelete( XinMenu * menu, int index )
|
|
{
|
|
/*END*/
|
|
if ( index < 0 || index >= menu->nbr_items )
|
|
return FALSE;
|
|
menu->nbr_items--;
|
|
if ( index < menu->nbr_items )
|
|
memmove( menu->items + index, menu->items + index + 1,
|
|
( menu->nbr_items - index ) * sizeof( XinMenuItem ) );
|
|
return TRUE;
|
|
/*START*/
|
|
}
|
|
|
|
/*
|
|
this function allocates and duplicates a menu hierarchy
|
|
*/
|
|
XinMenu *
|
|
XinMenuDuplicate( XinMenu * menu )
|
|
{
|
|
/*END*/
|
|
XinMenu *new_menu = XinMemoryAlloc( sizeof( XinMenu ) );
|
|
|
|
new_menu->nbr_items = menu->nbr_items;
|
|
if ( menu->nbr_items != 0 )
|
|
new_menu->items = menu_clone_items( menu->nbr_items, menu->items );
|
|
else
|
|
new_menu->items = NULL;
|
|
return new_menu;
|
|
/*START*/
|
|
}
|
|
|
|
/*
|
|
this function frees a menu hierarchy
|
|
*/
|
|
void
|
|
XinMenuFree( XinMenu * menu )
|
|
{
|
|
/*END*/
|
|
if ( menu->items != NULL )
|
|
{
|
|
menu_free_items( menu->nbr_items, menu->items );
|
|
XinMemoryFree( menu->items );
|
|
}
|
|
XinMemoryFree( menu );
|
|
/*START*/
|
|
}
|
|
|
|
/*
|
|
this function adds the specified child menu item into a parent menu item.
|
|
It does not change the menu for any window.
|
|
*/
|
|
XinMenuItem *
|
|
XinMenuItemAdd( XinMenuItem * parent, int index, XinMenuItem * child )
|
|
{
|
|
/*END*/
|
|
if ( index < 0 || index > parent->nbr_children )
|
|
return NULL;
|
|
|
|
if ( parent->nbr_children == 0 )
|
|
{
|
|
parent->nbr_children = 1;
|
|
parent->children = XinMemoryAlloc( sizeof( XinMenuItem ) );
|
|
}
|
|
else
|
|
{
|
|
parent->nbr_children++;
|
|
parent->children = XinMemoryRealloc( parent->children, parent->nbr_children
|
|
* sizeof( XinMenuItem ) );
|
|
}
|
|
if ( index < parent->nbr_children - 1 )
|
|
memmove( parent->children + index + 1, parent->children + index,
|
|
( parent->nbr_children - index - 1 ) * sizeof( XinMenuItem ) );
|
|
memmove( parent->children + index, child, sizeof( XinMenuItem ) );
|
|
child = parent->children + index;
|
|
if ( child->text != NULL )
|
|
child->text = copy_menu_text( child->text );
|
|
if ( child->nbr_children != 0 )
|
|
child->children = menu_clone_items( child->nbr_children, child->children );
|
|
return child;
|
|
/*START*/
|
|
}
|
|
|
|
/*
|
|
this function creates a menu item from a text string.
|
|
*/
|
|
XinMenuItem *
|
|
XinMenuItemCreate( char *text )
|
|
{
|
|
/*END*/
|
|
XinMenuItem *item = XinMemoryZeroAlloc( sizeof( XinMenuItem ) );
|
|
|
|
if ( text != NULL )
|
|
item->text = copy_menu_text( text );
|
|
return item;
|
|
/*START*/
|
|
}
|
|
|
|
/*
|
|
this function allocates and duplicates a menu item.
|
|
*/
|
|
XinMenuItem *
|
|
XinMenuItemDuplicate( XinMenuItem * item )
|
|
{
|
|
/*END*/
|
|
XinMenuItem *new_item = XinMemoryAlloc( sizeof( XinMenuItem ) );
|
|
|
|
memmove( new_item, item, sizeof( XinMenuItem ) );
|
|
if ( item->nbr_children != 0 )
|
|
new_item->children = menu_clone_items( item->nbr_children,
|
|
item->children );
|
|
if ( item->text != NULL )
|
|
new_item->text = copy_menu_text( item->text );
|
|
return new_item;
|
|
/*START*/
|
|
}
|
|
|
|
/*
|
|
this function deletes a child menu item from a parent menu item.
|
|
It does not change the menu for any window.
|
|
*/
|
|
BOOLEAN
|
|
XinMenuItemDelete( XinMenuItem * item, int index )
|
|
{
|
|
/*END*/
|
|
if ( index < 0 || index >= item->nbr_children )
|
|
return FALSE;
|
|
item->nbr_children--;
|
|
if ( index < item->nbr_children )
|
|
memmove( item->children + index, item->children + index + 1,
|
|
( item->nbr_children - index ) * sizeof( XinMenuItem ) );
|
|
return TRUE;
|
|
/*START*/
|
|
}
|
|
|
|
/*
|
|
this function frees the memory for a menu item.
|
|
*/
|
|
void
|
|
XinMenuItemFree( XinMenuItem * item )
|
|
{
|
|
/*END*/
|
|
if ( item->nbr_children != 0 )
|
|
{
|
|
menu_free_items( item->nbr_children, item->children );
|
|
XinMemoryFree( item->children );
|
|
}
|
|
if ( item->text != NULL )
|
|
XinMemoryFree( item->text );
|
|
XinMemoryFree( item );
|
|
/*START*/
|
|
}
|
|
|
|
/*
|
|
this function sets the text on a menu item.
|
|
It does not change the menu for any window.
|
|
*/
|
|
void
|
|
XinMenuItemTextSet( XinMenuItem * item, char *text )
|
|
{
|
|
/*END*/
|
|
if ( item->text != NULL )
|
|
XinMemoryFree( item->text );
|
|
if ( text == NULL )
|
|
item->text = NULL;
|
|
else
|
|
item->text = copy_menu_text( text );
|
|
/*START*/
|
|
}
|
|
|
|
/*END*/
|
|
#if XIWS == XIWS_XM
|
|
long
|
|
XinWindowGetWidget( XinWindow win )
|
|
{
|
|
return xvt_vobj_get_attr( ( WINDOW ) win, ATTR_X_WIDGET );
|
|
}
|
|
|
|
#endif
|
|
|
|
/*START*/
|
|
/*
|
|
this function returns whether the bold attribute is set for a font.
|
|
*/
|
|
BOOLEAN
|
|
XinFontBoldGet( XinFont * font )
|
|
{
|
|
return font->bold;
|
|
}
|
|
|
|
/*
|
|
this function sets the bold attribute for a font.
|
|
*/
|
|
void
|
|
XinFontBoldSet( XinFont * font, BOOLEAN flag )
|
|
{
|
|
/*END*/
|
|
unsigned long attrib;
|
|
|
|
font->bold = flag;
|
|
attrib = xvt_font_get_style( font->xvt_fntid );
|
|
if ( flag )
|
|
attrib |= XVT_FS_BOLD;
|
|
else
|
|
attrib &= ~XVT_FS_BOLD;
|
|
xvt_font_set_style( font->xvt_fntid, attrib );
|
|
/*START*/
|
|
}
|
|
|
|
/*
|
|
this function compares two fonts, and if they will have exactly the same
|
|
appearance, the function returns TRUE; if not, FALSE.
|
|
*/
|
|
BOOLEAN
|
|
XinFontCompare( XinFont * f1, XinFont * f2 )
|
|
{
|
|
/*END*/
|
|
char buf1[FONT_ATTR_SIZE];
|
|
char buf2[FONT_ATTR_SIZE];
|
|
|
|
if ( f1 == f2 )
|
|
return TRUE;
|
|
|
|
if ( !f1->from_xvt_font && !f2->from_xvt_font )
|
|
return ( f1->family == f2->family && f1->size == f2->size
|
|
&& f1->bold == f2->bold && f1->italic == f2->italic );
|
|
|
|
/* XVT internal compare */
|
|
|
|
/* If both font have valid native descs, compare those */
|
|
if ( xvt_font_get_native_desc( f1->xvt_fntid, buf1, FONT_ATTR_SIZE ) &&
|
|
xvt_font_get_native_desc( f2->xvt_fntid, buf2, FONT_ATTR_SIZE ) )
|
|
{
|
|
if ( *buf1 && *buf2 )
|
|
return ( strncmp( buf1, buf2, FONT_ATTR_SIZE ) == 0 );
|
|
}
|
|
|
|
/* If one of the fonts lacks nd, compare portable attrs */
|
|
if ( xvt_font_get_style( f1->xvt_fntid ) != xvt_font_get_style( f2->xvt_fntid ) )
|
|
return FALSE;
|
|
|
|
if ( xvt_font_get_size( f1->xvt_fntid ) != xvt_font_get_size( f2->xvt_fntid ) )
|
|
return FALSE;
|
|
|
|
if ( !xvt_font_get_family( f1->xvt_fntid, buf1, FONT_ATTR_SIZE ) )
|
|
return FALSE;
|
|
if ( !xvt_font_get_family( f2->xvt_fntid, buf2, FONT_ATTR_SIZE ) )
|
|
return FALSE;
|
|
|
|
return ( strncmp( buf1, buf2, FONT_ATTR_SIZE ) == 0 );
|
|
/*START*/
|
|
}
|
|
|
|
/*
|
|
this function creates a new font and initializes it with
|
|
a copy of the "Source" font, unless "Source" is NULL.
|
|
*/
|
|
void
|
|
XinFontCopy( XinFont ** Dest, XinFont * Source )
|
|
{
|
|
/*END*/
|
|
XinFont *new_font;
|
|
|
|
if ( Source == NULL )
|
|
*Dest = NULL;
|
|
else
|
|
{
|
|
new_font = XinMemoryAlloc( sizeof( XinFont ) );
|
|
*Dest = new_font;
|
|
*new_font = *Source;
|
|
new_font->xvt_fntid = xvt_font_create( );
|
|
xvt_font_copy( new_font->xvt_fntid, Source->xvt_fntid,
|
|
( unsigned long ) XVT_FA_ALL );
|
|
}
|
|
/*START*/
|
|
}
|
|
|
|
/*
|
|
this function allocates (creates) a font. after allocating the font,
|
|
the module using Xin may set the family, set the size, bold style,
|
|
italic style, and map the font to a window.
|
|
*/
|
|
XinFont *
|
|
XinFontCreate( void )
|
|
{
|
|
/*END*/
|
|
XinFont *xin_font;
|
|
|
|
xin_font = XinMemoryZeroAlloc( sizeof( XinFont ) );
|
|
xin_font->xvt_fntid = xvt_font_create( );
|
|
return xin_font;
|
|
/*START*/
|
|
}
|
|
|
|
/*
|
|
this function destroys a font
|
|
*/
|
|
void
|
|
XinFontDestroy( XinFont * font )
|
|
{
|
|
/*END*/
|
|
xvt_font_destroy( font->xvt_fntid );
|
|
XinMemoryFree( font );
|
|
/*START*/
|
|
}
|
|
|
|
/*
|
|
this function returns the family for a font. If the font was selected
|
|
from a dialog, then XinFontFamilyOther may be returned.
|
|
*/
|
|
XinFontFamily
|
|
XinFontFamilyGet( XinFont * font )
|
|
{
|
|
return font->family;
|
|
}
|
|
|
|
/*
|
|
this function sets the family for a font.
|
|
*/
|
|
void
|
|
XinFontFamilySet( XinFont * font, XinFontFamily family )
|
|
{
|
|
/*END*/
|
|
font->family = family;
|
|
switch ( family )
|
|
{
|
|
case XinFontFamilySystem:
|
|
xvt_font_set_family( font->xvt_fntid, XVT_FFN_SYSTEM );
|
|
break;
|
|
case XinFontFamilyFixed:
|
|
xvt_font_set_family( font->xvt_fntid, XVT_FFN_COURIER );
|
|
break;
|
|
case XinFontFamilyTimes:
|
|
xvt_font_set_family( font->xvt_fntid, XVT_FFN_TIMES );
|
|
break;
|
|
case XinFontFamilyHelvetica:
|
|
xvt_font_set_family( font->xvt_fntid, XVT_FFN_HELVETICA );
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
/*START*/
|
|
}
|
|
|
|
/*
|
|
this function returns the mapped state of a font.
|
|
*/
|
|
BOOLEAN
|
|
XinFontIsMapped( XinFont * font )
|
|
{
|
|
/*END*/
|
|
return xvt_font_is_mapped( font->xvt_fntid );
|
|
/*START*/
|
|
}
|
|
|
|
/*
|
|
this function returns the italic style state for a font.
|
|
*/
|
|
BOOLEAN
|
|
XinFontItalicGet( XinFont * font )
|
|
{
|
|
return font->italic;
|
|
}
|
|
|
|
/*
|
|
this function sets the italic style state for a font.
|
|
*/
|
|
void
|
|
XinFontItalicSet( XinFont * font, BOOLEAN flag )
|
|
{
|
|
/*END*/
|
|
unsigned long attrib;
|
|
|
|
font->italic = flag;
|
|
attrib = xvt_font_get_style( font->xvt_fntid );
|
|
if ( flag )
|
|
attrib |= XVT_FS_ITALIC;
|
|
else
|
|
attrib &= ~XVT_FS_ITALIC;
|
|
xvt_font_set_style( font->xvt_fntid, attrib );
|
|
/*START*/
|
|
}
|
|
|
|
/*
|
|
this function gets the vertical metrics for a font. the font must be mapped to
|
|
a window in order to call this function.
|
|
*/
|
|
void
|
|
XinFontMetricsGet( XinFont * Font, int *Leading, int *Ascent, int *Descent )
|
|
{
|
|
/*END*/
|
|
xvt_font_get_metrics( Font->xvt_fntid, Leading, Ascent,
|
|
Descent );
|
|
/*START*/
|
|
}
|
|
|
|
/*
|
|
this function returns the point size for a font.
|
|
*/
|
|
int
|
|
XinFontSizeGet( XinFont * Font )
|
|
{
|
|
return Font->size;
|
|
}
|
|
|
|
/*
|
|
this function sets the point size for a font.
|
|
*/
|
|
void
|
|
XinFontSizeSet( XinFont * Font, int size )
|
|
{
|
|
/*END*/
|
|
Font->size = size;
|
|
xvt_font_set_size( Font->xvt_fntid, size );
|
|
/*START*/
|
|
}
|
|
|
|
/*
|
|
this function gets the width in pixels for the specified text, based on the
|
|
specified font. the font must be mapped to a window. if 'len' is equal to
|
|
-1, then this function returns the pixel length of the entire string pointed
|
|
to by text. if 'len' is not equal to -1, then this function returns the pixel
|
|
length of the first 'len' characters of the string in 'text'
|
|
*/
|
|
int
|
|
XinFontTextWidthGet( XinFont * font, char *text, int len )
|
|
{
|
|
/*END*/
|
|
XVT_FNTID font_id = font->xvt_fntid;
|
|
WINDOW win;
|
|
|
|
if ( !xvt_font_is_mapped( font_id ) )
|
|
return 0;
|
|
win = xvt_font_get_win( font_id );
|
|
xvt_dwin_set_font( win, font_id );
|
|
return xvt_dwin_get_text_width( win, text, len );
|
|
/*START*/
|
|
}
|
|
|
|
/*
|
|
this function destroys (frees) a bitmap.
|
|
*/
|
|
void
|
|
XinBitmapDestroy( XinBitmap * bitmap )
|
|
{
|
|
/*END*/
|
|
xvt_image_destroy( bitmap->image );
|
|
XinMemoryFree( bitmap );
|
|
/*START*/
|
|
}
|
|
|
|
/*END*/
|
|
/*START*/
|
|
/*
|
|
this function allocates, and reads a bitmap from the specified file.
|
|
*/
|
|
XinBitmap *
|
|
XinBitmapRead( char *filename )
|
|
{
|
|
/*END*/
|
|
XVT_IMAGE image;
|
|
XinBitmap *bitmap;
|
|
|
|
if ( ( image = xvt_image_read( filename ) ) == NULL )
|
|
return NULL;
|
|
bitmap = XinMemoryAlloc( sizeof( XinBitmap ) );
|
|
bitmap->image = image;
|
|
if ( xin_palette == NULL )
|
|
xin_palette = xvt_palet_create( XVT_PALETTE_USER, 0 );
|
|
xvt_palet_add_colors_from_image( xin_palette, bitmap->image );
|
|
xvt_vobj_set_palet( SCREEN_WIN, xin_palette );
|
|
return bitmap;
|
|
/*START*/
|
|
}
|
|
|
|
/*START*/
|
|
/*
|
|
this function allocates, and reads a bitmap from the resource file.
|
|
*/
|
|
XinBitmap *
|
|
XinBitmapReadRes( short id)
|
|
{
|
|
/*END*/
|
|
XVT_IMAGE image;
|
|
XinBitmap *bitmap;
|
|
|
|
if ( ( image = xvt_res_get_image( id ) ) == NULL )
|
|
return NULL;
|
|
bitmap = XinMemoryAlloc( sizeof( XinBitmap ) );
|
|
bitmap->image = image;
|
|
if ( xin_palette == NULL )
|
|
xin_palette = xvt_palet_create( XVT_PALETTE_USER, 0 );
|
|
xvt_palet_add_colors_from_image( xin_palette, bitmap->image );
|
|
xvt_vobj_set_palet( SCREEN_WIN, xin_palette );
|
|
return bitmap;
|
|
/*START*/
|
|
}
|
|
|
|
/*
|
|
this function returns the width and height of the
|
|
specified bitmap.
|
|
*/
|
|
void
|
|
XinBitmapSizeGet( XinBitmap * bitmap, short *pw, short *ph )
|
|
{
|
|
/*END*/
|
|
xvt_image_get_dimensions( bitmap->image, pw, ph );
|
|
/*START*/
|
|
}
|
|
|
|
/*
|
|
this function returns the next band to be printed. see the discussion on printing
|
|
and banding above for more details.
|
|
*/
|
|
XinRect *
|
|
XinPrintBandNext( void )
|
|
{
|
|
/*END*/
|
|
return ( XinRect * ) xvt_print_get_next_band( );
|
|
/*START*/
|
|
}
|
|
|
|
/*
|
|
this function is called when a page has been completely drawn. it causes the page
|
|
to be sent to the printer.
|
|
*/
|
|
BOOLEAN
|
|
XinPrintPageEnd( XinPrintRecord * rec )
|
|
{
|
|
/*END*/
|
|
return xvt_print_close_page( ( PRINT_RCD * ) rec );
|
|
/*START*/
|
|
}
|
|
|
|
/*
|
|
this function is called when the module using Xin is about to print a page.
|
|
*/
|
|
BOOLEAN
|
|
XinPrintPageStart( XinPrintRecord * rec )
|
|
{
|
|
/*END*/
|
|
return xvt_print_open_page( ( PRINT_RCD * ) rec );
|
|
/*START*/
|
|
}
|
|
|
|
/*
|
|
this function allocates and initializes a print record. after this function has
|
|
been called, then XinDialogPrinterSetup can be called, getting the user's
|
|
instructions on which printer to print the document, whether the document is printed
|
|
in landscape or portrait mode, etc. then, the filled in XinPrintRecord is passed
|
|
to XinPrintPageStart, XinPrintBandNext, and XinPrintPageEnd.
|
|
The returned print record will contain the default printer setup.
|
|
*/
|
|
XinPrintRecord *
|
|
XinPrintRecordCreate( int *p_size )
|
|
{
|
|
/*END*/
|
|
return ( XinPrintRecord * ) xvt_print_create( p_size );
|
|
/*START*/
|
|
}
|
|
|
|
/*
|
|
this function frees up the memory and any resources
|
|
allocated for a print record.
|
|
*/
|
|
void
|
|
XinPrintRecordDestroy( XinPrintRecord * rec )
|
|
{
|
|
/*END*/
|
|
xvt_print_destroy( ( PRINT_RCD * ) rec );
|
|
/*START*/
|
|
}
|
|
|
|
/*
|
|
this function returns whether a print record still contains valid information. an
|
|
example of invalid information is if the print record contains information on a
|
|
printer that is no longer attached to the computer.
|
|
*/
|
|
BOOLEAN
|
|
XinPrintRecordValidate( XinPrintRecord * rec )
|
|
{
|
|
/*END*/
|
|
return xvt_print_is_valid( ( PRINT_RCD * ) rec );
|
|
/*START*/
|
|
}
|
|
|
|
/*
|
|
This function gets the height and width of the printer area in pixels (or dots),
|
|
and the vertical and horizontal resolution in pixels per inch.
|
|
*/
|
|
|
|
void
|
|
XinPrintRecordMetricsGet( XinPrintRecord * rec, long * height, long * width,
|
|
long * vres, long * hres )
|
|
{
|
|
/*END*/
|
|
xvt_app_escape(XVT_ESC_GET_PRINTER_INFO, ( PRINT_RCD * ) rec, height,
|
|
width, vres, hres);
|
|
/*START*/
|
|
}
|
|
|
|
/*
|
|
on some implementations, it is necessary, or desirable, to start a
|
|
separate thread for printing.
|
|
|
|
if threaded printing is implemented, then the thread should be started so that it
|
|
calls 'func' as soon as it starts. 'func' then does the actual printing.
|
|
|
|
if threaded printing is not implemented, then this function simply calls 'func'.
|
|
*/
|
|
BOOLEAN
|
|
XinPrintThreadStart( XinPrintHandler func, long app_data )
|
|
{
|
|
/*END*/
|
|
return xvt_print_start_thread( func, app_data );
|
|
/*START*/
|
|
}
|
|
|
|
/*
|
|
this function creates a print window.
|
|
*/
|
|
XinWindow
|
|
XinPrintWindowCreate( XinPrintRecord * rec, char *title )
|
|
{
|
|
/*END*/
|
|
return ( XinWindow ) xvt_print_create_win( ( PRINT_RCD * ) rec, title );
|
|
/*START*/
|
|
}
|
|
|
|
/*
|
|
this function destroys a print window.
|
|
*/
|
|
void
|
|
XinPrintWindowDestroy( XinWindow win )
|
|
{
|
|
/*END*/
|
|
xvt_vobj_destroy( ( WINDOW ) win );
|
|
/*START*/
|
|
}
|
|
|
|
/*END*/
|
|
#if XIWS == XIWS_WIN
|
|
static char *
|
|
find_last_slash( char *str )
|
|
{
|
|
char *p = str + strlen( str ) - 1;
|
|
|
|
if ( *str == '\0' )
|
|
return NULL;
|
|
|
|
while ( p != str )
|
|
{
|
|
if ( *p == '\\' || *p == '/' )
|
|
return p;
|
|
p--;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static void
|
|
copy_leading_path( char *path, char *dest )
|
|
{
|
|
char *p = find_last_slash( path );
|
|
|
|
if ( p != NULL )
|
|
{
|
|
int len = ( int ) ( p - path );
|
|
|
|
memmove( dest, path, len );
|
|
dest[len] = '\0';
|
|
}
|
|
else
|
|
*dest = '\0';
|
|
}
|
|
|
|
#endif
|
|
|
|
/*START*/
|
|
/*
|
|
This function returns the full directory path based on "full_name", which
|
|
may contain relative directory information.
|
|
|
|
The implementation is complete.
|
|
*/
|
|
BOOLEAN
|
|
XinDirectoryAbsoluteGet( char *full_name, XinDirectory * dir )
|
|
{
|
|
/*END*/
|
|
#if XIWS == XIWS_WIN
|
|
XinDirectory current_dir;
|
|
|
|
if ( isalpha( full_name[0] ) && full_name[1] == ':' )
|
|
{ /* Drive letter - find current directory for
|
|
* that drive */
|
|
if ( full_name[2] == '\\' || full_name[2] == '/' )
|
|
{ /* Got full path name */
|
|
copy_leading_path( full_name, ( char * ) dir );
|
|
}
|
|
else
|
|
{ /* Relative path for that drive. */
|
|
XinDirectory save_dir;
|
|
char *p_dir = ( char * ) dir;
|
|
|
|
if ( !XinDirectoryCurrentGet( &save_dir ) )
|
|
return FALSE;
|
|
current_dir[0] = full_name[0];
|
|
current_dir[1] = ':';
|
|
current_dir[2] = '.';
|
|
current_dir[3] = '\0';
|
|
if ( !XinDirectoryCurrentSet( ¤t_dir ) )
|
|
return FALSE;
|
|
if ( !XinDirectoryCurrentGet( ¤t_dir ) )
|
|
{
|
|
XinDirectoryCurrentSet( &save_dir );
|
|
return FALSE;
|
|
}
|
|
XinDirectoryCurrentSet( &save_dir );
|
|
strcpy( p_dir, current_dir );
|
|
p_dir += strlen( p_dir );
|
|
*p_dir++ = '/';
|
|
copy_leading_path( full_name + 2, p_dir );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
char *p_dir = ( char * ) dir;
|
|
|
|
if ( !XinDirectoryCurrentGet( ¤t_dir ) )
|
|
return FALSE;
|
|
if ( full_name[0] == '\\' || full_name[0] == '/' )
|
|
{ /* Got full path, but need drive */
|
|
*p_dir++ = current_dir[0];
|
|
*p_dir++ = ':';
|
|
}
|
|
else
|
|
{ /* Relative path */
|
|
strcpy( p_dir, current_dir );
|
|
p_dir += strlen( p_dir );
|
|
*p_dir++ = '/';
|
|
}
|
|
copy_leading_path( full_name, p_dir );
|
|
}
|
|
{
|
|
/* copy_leading_path() can copy nothing, but we appended a '/' for it
|
|
* regardless. */
|
|
char *p_dir = ( char * ) dir;
|
|
|
|
p_dir += strlen( ( char * ) dir ) - 1;
|
|
if ( *p_dir == '/' )
|
|
{
|
|
*p_dir = '\0';
|
|
}
|
|
}
|
|
#elif XIWS == XIWS_MAC
|
|
char *p_dir;
|
|
|
|
/* Leading colon means it is relative */
|
|
if ( full_name[0] == ':' )
|
|
{
|
|
if ( !XinDirectoryCurrentGet( dir ) )
|
|
return FALSE;
|
|
p_dir = ( char * ) dir + strlen( ( char * ) dir );
|
|
}
|
|
else
|
|
{
|
|
*( char * ) dir = '\0';
|
|
p_dir = ( char * ) dir;
|
|
}
|
|
|
|
/* Directory goes to last colon. */
|
|
{
|
|
char *p = strrchr( full_name, ':' );
|
|
|
|
if ( p != NULL )
|
|
{
|
|
int len = ( int ) ( p - full_name );
|
|
|
|
memmove( p_dir, full_name, len );
|
|
p_dir[len] = '\0';
|
|
}
|
|
}
|
|
#else
|
|
char *p_dir;
|
|
|
|
/* Leading slash means it is absolute */
|
|
if ( full_name[0] != '/' )
|
|
{
|
|
if ( !XinDirectoryCurrentGet( dir ) )
|
|
return FALSE;
|
|
p_dir = ( char * ) dir + strlen( ( char * ) dir );
|
|
}
|
|
else
|
|
{
|
|
*( char * ) dir = '\0';
|
|
p_dir = ( char * ) dir;
|
|
}
|
|
|
|
/* Directory goes to last slash. */
|
|
{
|
|
char *p = strrchr( full_name, '/' );
|
|
|
|
if ( p != NULL )
|
|
{
|
|
int len = ( int ) ( p - full_name - 1 );
|
|
|
|
memmove( p_dir, full_name, len );
|
|
p_dir[len] = '\0';
|
|
}
|
|
}
|
|
|
|
#endif
|
|
return TRUE;
|
|
/*START*/
|
|
}
|
|
|
|
/*
|
|
this function gets the current directory, and puts the result in an
|
|
XinDirectory.
|
|
*/
|
|
BOOLEAN
|
|
XinDirectoryCurrentGet( XinDirectory * dir )
|
|
{
|
|
/*END*/
|
|
return ( xvt_fsys_get_dir( ( DIRECTORY * ) dir ) );
|
|
/*START*/
|
|
}
|
|
|
|
/*
|
|
given an XinDirectory, this function sets the current directory.
|
|
*/
|
|
BOOLEAN
|
|
XinDirectoryCurrentSet( XinDirectory * dir )
|
|
{
|
|
/*END*/
|
|
return ( xvt_fsys_set_dir( ( DIRECTORY * ) dir ) );
|
|
/*START*/
|
|
}
|
|
|
|
/*
|
|
given an XinFileListSpec, this function returns the list of files that match the
|
|
spec.
|
|
*/
|
|
XinFileList *
|
|
XinFileListGet( XinFileListSpec * spec )
|
|
{
|
|
/*END*/
|
|
static XinFileList files = {0, NULL};
|
|
|
|
int num;
|
|
SLIST slist;
|
|
SLIST_ELT element;
|
|
char **p_file_name;
|
|
|
|
for ( num = 0; num < files.nbr_files; num++ )
|
|
XinMemoryFree( files.file_names[num] );
|
|
XinMemoryFree( files.file_names );
|
|
files.nbr_files = 0;
|
|
files.file_names = NULL;
|
|
|
|
if ( spec == NULL )
|
|
return NULL;
|
|
|
|
if ( ( slist = xvt_fsys_list_files( spec->dirs_only ? DIR_TYPE : spec->type,
|
|
spec->pattern, spec->include_dirs ) ) == NULL )
|
|
return NULL;
|
|
files.nbr_files = xvt_slist_count( slist );
|
|
files.file_names = XinMemoryAlloc( files.nbr_files * sizeof( char * ) );
|
|
p_file_name = files.file_names;
|
|
for ( element = xvt_slist_get_first( slist ); element != NULL;
|
|
element = xvt_slist_get_next( slist, element ), p_file_name++ )
|
|
{
|
|
long el_type;
|
|
char *text;
|
|
int len;
|
|
|
|
text = xvt_slist_get( slist, element, &el_type );
|
|
len = strlen( text ) + 1;
|
|
*p_file_name = XinMemoryAlloc( len );
|
|
memmove( *p_file_name, text, len );
|
|
}
|
|
xvt_slist_destroy( slist );
|
|
|
|
return &files;
|
|
/*START*/
|
|
}
|
|
|
|
static XinErrorHandler error_handler = NULL;
|
|
|
|
/*
|
|
the module using Xin calls this function when it encounters an error, and needs
|
|
to take some action. there are two possible states of severity:
|
|
XinSeverityWarning and XinSeverityFatal. if the severity is XinSeverityWarning,
|
|
then this function puts up a error message box. if the severity is
|
|
XinSeverityFatal, then this function puts up an error message box, then terminates
|
|
the application.
|
|
|
|
the module using Xin may set an error handler function by calling XinErrorHandlerSet.
|
|
if it does, then the new error handler is called. if the new error handler function
|
|
returns TRUE, then this function should terminate the application.
|
|
|
|
the following implementation is complete.
|
|
*/
|
|
void
|
|
XinError( int errcode, XinSeverity severity, long app_data )
|
|
{
|
|
BOOLEAN terminate = ( severity == XinSeverityFatal );
|
|
|
|
if ( error_handler != NULL )
|
|
terminate = ( *error_handler ) ( errcode, severity, app_data );
|
|
if ( terminate )
|
|
XinAppTerminate( );
|
|
}
|
|
|
|
/*
|
|
this function gets and returns the Xin error handling function.
|
|
*/
|
|
XinErrorHandler
|
|
XinErrorHandlerGet( void )
|
|
{
|
|
return error_handler;
|
|
}
|
|
|
|
/*
|
|
this function sets the Xin error handling function.
|
|
*/
|
|
void
|
|
XinErrorHandlerSet( XinErrorHandler handler )
|
|
{
|
|
error_handler = handler;
|
|
}
|
|
|
|
/*END*/
|
|
|
|
void
|
|
XinInitBuffer( )
|
|
{
|
|
if ( xin_buffer == NULL )
|
|
xin_buffer = XinMemoryAlloc( TEMP_BUFFER_SIZE );
|
|
}
|
|
|
|
void
|
|
XinIconSizeGet( int icon_rid, int *widthp, int *heightp )
|
|
{
|
|
NOREF( icon_rid );
|
|
*widthp = 32;
|
|
*heightp = 32;
|
|
}
|
|
|
|
#if XIWS == XIWS_WIN || XIWS == XIWS_PM
|
|
|
|
static struct
|
|
{
|
|
short xi_key;
|
|
short v_key;
|
|
BOOLEAN shift;
|
|
}
|
|
|
|
vk_table[] =
|
|
{
|
|
#if XIWS == XIWS_WIN
|
|
{
|
|
'\033', VK_ESCAPE, FALSE
|
|
},
|
|
{
|
|
XI_KEY_BTAB, VK_BACK, TRUE,
|
|
},
|
|
{
|
|
'\r', VK_RETURN, FALSE
|
|
},
|
|
{
|
|
XI_KEY_PREV, VK_PRIOR, FALSE
|
|
},
|
|
{
|
|
XI_KEY_NEXT, VK_NEXT, FALSE
|
|
},
|
|
#endif
|
|
#if XIWS == XIWS_PM
|
|
{
|
|
'\033', VK_ESC, FALSE
|
|
},
|
|
{
|
|
XI_KEY_BTAB, VK_BACKTAB, TRUE,
|
|
},
|
|
{
|
|
'\r', VK_ENTER, FALSE
|
|
},
|
|
{
|
|
XI_KEY_PREV, VK_PAGEUP, FALSE
|
|
},
|
|
{
|
|
XI_KEY_NEXT, VK_PAGEDOWN, FALSE
|
|
},
|
|
#endif
|
|
{
|
|
XI_KEY_DEL, VK_DELETE, FALSE
|
|
},
|
|
{
|
|
'\t', VK_TAB, FALSE
|
|
},
|
|
{
|
|
XI_KEY_END, VK_END, FALSE
|
|
},
|
|
{
|
|
XI_KEY_HOME, VK_HOME, FALSE
|
|
},
|
|
{
|
|
XI_KEY_LEFT, VK_LEFT, FALSE
|
|
},
|
|
{
|
|
XI_KEY_UP, VK_UP, FALSE
|
|
},
|
|
{
|
|
XI_KEY_RIGHT, VK_RIGHT, FALSE
|
|
},
|
|
{
|
|
XI_KEY_DOWN, VK_DOWN, FALSE
|
|
},
|
|
{
|
|
XI_KEY_F1, VK_F1, FALSE
|
|
},
|
|
{
|
|
XI_KEY_F2, VK_F2, FALSE
|
|
},
|
|
{
|
|
XI_KEY_F3, VK_F3, FALSE
|
|
},
|
|
{
|
|
XI_KEY_F4, VK_F4, FALSE
|
|
},
|
|
{
|
|
XI_KEY_F5, VK_F5, FALSE
|
|
},
|
|
{
|
|
XI_KEY_F6, VK_F6, FALSE
|
|
},
|
|
{
|
|
XI_KEY_F7, VK_F7, FALSE
|
|
},
|
|
{
|
|
XI_KEY_F8, VK_F8, FALSE
|
|
},
|
|
{
|
|
XI_KEY_F9, VK_F9, FALSE
|
|
},
|
|
{
|
|
XI_KEY_F10, VK_F10, FALSE
|
|
},
|
|
{
|
|
XI_KEY_F11, VK_F11, FALSE
|
|
},
|
|
{
|
|
XI_KEY_F12, VK_F12, FALSE
|
|
},
|
|
{
|
|
0, 0, FALSE
|
|
}
|
|
};
|
|
|
|
#endif
|
|
|
|
#if XIWS == XIWS_WIN
|
|
BOOLEAN XVT_CALLCONV1
|
|
xin_xvt_win_raw_event_hook( MSG * pmsg, HWND * phwnd )
|
|
{
|
|
NOREF( phwnd );
|
|
switch ( pmsg->message )
|
|
{
|
|
case WM_SYSKEYDOWN:
|
|
{
|
|
WindowInfo *ehlt;
|
|
|
|
ehlt = find_window_info_from_HWND( pmsg->hwnd );
|
|
if ( ehlt != NULL )
|
|
{
|
|
XinEvent event;
|
|
|
|
MEMCLEAR( event );
|
|
|
|
event.type = XinEventCharacter;
|
|
event.v.character.ch = pmsg->wParam & 0xff;
|
|
event.v.character.shift = FALSE;
|
|
event.v.character.control = FALSE;
|
|
event.v.character.alt = TRUE;
|
|
event.v.character.consumed = FALSE;
|
|
if ( event.v.character.ch != 18 )
|
|
{
|
|
int cnt;
|
|
|
|
for ( cnt = 0; vk_table[cnt].xi_key != 0; ++cnt )
|
|
{
|
|
if ( vk_table[cnt].v_key == event.v.character.ch )
|
|
{
|
|
event.v.character.ch = vk_table[cnt].xi_key;
|
|
event.v.character.shift = vk_table[cnt].shift;
|
|
break;
|
|
}
|
|
}
|
|
{
|
|
EVENT* old_cur_event = cur_xvt_event;
|
|
EVENT xvt_event;
|
|
xvt_event.v.chr.ch = pmsg->wParam & 0xff;
|
|
xvt_event.v.chr.shift = FALSE;
|
|
xvt_event.v.chr.control = FALSE;
|
|
|
|
cur_xvt_event = &xvt_event;
|
|
( *ehlt->event_handler ) ( ( XinWindow ) ehlt->win, &event );
|
|
cur_xvt_event = old_cur_event;
|
|
}
|
|
#if XVT_CHECK_VERSION(4, 50, 0)
|
|
return !event.v.character.consumed;
|
|
#else
|
|
return event.v.character.consumed;
|
|
#endif
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
#if XVT_CHECK_VERSION(4, 50, 0)
|
|
return TRUE;
|
|
#else
|
|
return FALSE;
|
|
#endif
|
|
}
|
|
|
|
#endif
|
|
|
|
#if XIWS == XIWS_PM
|
|
BOOLEAN XVT_CALLCONV1
|
|
xin_xvt_pm_raw_event_hook( QMSG * pmsg )
|
|
{
|
|
if ( pmsg->msg == ( ULONG ) WM_CHAR &&
|
|
( ( ( USHORT ) SHORT1FROMMP( pmsg->mp1 ) & KC_ALT ) != 0 ) )
|
|
{
|
|
WindowInfo *ehlt;
|
|
|
|
ehlt = find_window_info_from_HWND( pmsg->hwnd );
|
|
if ( ehlt != NULL )
|
|
{
|
|
XinEvent event;
|
|
|
|
MEMCLEAR( event );
|
|
|
|
event.type = XinEventCharacter;
|
|
event.v.character.ch = LONGFROMMP( pmsg->mp2 );
|
|
event.v.character.shift = FALSE;
|
|
event.v.character.control = FALSE;
|
|
event.v.character.alt = TRUE;
|
|
event.v.character.consumed = FALSE;
|
|
|
|
if ( event.v.character.ch != 18 )
|
|
{
|
|
int cnt;
|
|
|
|
for ( cnt = 0; vk_table[cnt].xi_key != 0; ++cnt )
|
|
{
|
|
if ( vk_table[cnt].v_key == event.v.character.ch )
|
|
{
|
|
event.v.character.ch = vk_table[cnt].xi_key;
|
|
event.v.character.shift = vk_table[cnt].shift;
|
|
break;
|
|
}
|
|
}
|
|
{
|
|
EVENT xvt_event;
|
|
EVENT* old_cur_event = cur_xvt_event;
|
|
xvt_event.v.chr.ch = LONGFROMMP( pmsg->mp2 );
|
|
xvt_event.v.chr.shift = FALSE;
|
|
xvt_event.v.chr.control = FALSE;
|
|
|
|
cur_xvt_event = &xvt_event;
|
|
( *ehlt->event_handler ) ( ( XinWindow ) ehlt->win, &event );
|
|
cur_xvt_event = old_cur_event;
|
|
}
|
|
return !event.v.character.consumed;
|
|
|
|
}
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
#endif
|
|
|
|
static char *xin_help_file_name = NULL;
|
|
|
|
/*START*/
|
|
/* Native help (only implemented on Windows - these calls do nothing elsewhere) */
|
|
|
|
void
|
|
XinHelpFileNameSet( char *filename )
|
|
{
|
|
/*END*/
|
|
if (xin_help_file_name != NULL)
|
|
XinMemoryFree( xin_help_file_name );
|
|
xin_help_file_name = (char *)XinMemoryAlloc( (strlen( filename ) + 1) * sizeof( char ) );
|
|
strcpy( xin_help_file_name, filename );
|
|
/*START*/
|
|
}
|
|
|
|
char *
|
|
XinHelpFileNameGet()
|
|
{
|
|
/*END*/
|
|
return xin_help_file_name;
|
|
/*START*/
|
|
}
|
|
|
|
/* This function only does anything on Windows. */
|
|
BOOLEAN
|
|
XinNativeHelp( XinWindow win, char *help_key )
|
|
{
|
|
/*END*/
|
|
#if XIWS == XIWS_WIN
|
|
if (xin_help_file_name != NULL && win != XI_NULL_WINDOW &&
|
|
help_key != NULL)
|
|
{
|
|
return WinHelp( (HWND)XinWindowNativeGet( win ), xin_help_file_name,
|
|
HELP_KEY, (long)help_key );
|
|
}
|
|
return FALSE;
|
|
#else
|
|
return FALSE;
|
|
#endif
|
|
}
|