Module Dfextclm.pkg
1//************************************************************************
2// Confidential Trade Secret.
3// Copyright (c) 1997 Data Access Corporation, Miami Florida
4// as an unpublished work. All rights reserved.
5// DataFlex is a registered trademark of Data Access Corporation.
6//
7//************************************************************************
8//************************************************************************
9//
10// $File name : dfExtClM.pkg
11// $File title : external class mixin support
12// Notice :
13// $Author(s) : John Tuohy
14//
15// $Rev History
16//
17// JJT 9/8/97 Revised
18// JJT 7/25/97 File Created
19//************************************************************************
20
21// This provides common mixin messages for hooking an external class
22// to a VDF class. This assumes that this external class will be mixed into
23// The main goal of this mixin is to sychronize the DataFlex focus event
24// with the windows focus event.
25// If is very important that a tool maker watches the focus change mechanism.
26// It is very easy to create a control that looks like it is working but is
27// An object takes the focus one of two ways: Either DataFlex gives it the
28// focus (keyboard or send activate) or Windows gives it the focus (mouse).
29// All of the internal DF classes makes sure that these two types of events
30// are synchronized. When using external controls you must make sure that this
31// is the case. Note that:
32// 1. When DF sends activate to an object it may not give it the windows
33// focus. This one can usually be seen by testing with keyboard navigation.
34// Currently, we are augmenting Set Focus to make this work right.
35// 2. When Windows gives the object the focus it may not tell DF about it.
36// You can not see this problem but you can test by getting the focus
37// property. If the focus is a different object than the object that
38// appears to have the focus, windows has given the object the focus
39// without telling DF. We use External_SetFocus (which is a notification
40// of a windows event) to check for this.
41// 3. You want to make sure that DF sends the same focus change events when
42// an external object gets the focus or when it loses it. In particular,
43// you want to make sure that Notify_Focus_Change is sent to both objects
44// passing the appropriate Fg. This is very important. It insures that
45// OnSetFocus and onKillFocus are sent along with a number of other messages
46// which maintain status-help and default action buttons. This requires
47// careful checking to see what is sent and what is not and this must be
48// tested with both keyboard (DF side) and mouse (windows side) navigation.
49// Set Focus, External_SetFocus and External_KillFocus all had to be
50// messed with to get this right.
51//
52// Currently,
53// 1. When the windows side takes the focus the DF side is not notified.
54// To make this work we sit on this message and send activate to the
55// DF side. We also need to send Notify_focus_Change (same needed
56// on a killFocus) because this is not getting sent.
57//
58// 2. There is a bug in the external class mechanism when used with
59// form objects. The DF Set_Focus message gets canceled. So we force
60// this through by sending a windows SetFocus. (This could change in
61// the future which could also affect #1's need to send notify
62// messages).
63//
64// 3. We hook into Page_object to force it to send PreInitializeWindow,
65// initializeWindow (both whose functionality must be provided) and
66// Shadow_display. Normally InitializeWindow is required to move
67// DF properties into the newly created windows control. PreIntializeWindow
68// is needed when windows styles must be set before creating the control.
69// Shadow_Display sends Enable_Window which normally requires not
70// additional code. Enable_Window if provided to support shadowing of
71// objects.
72// NOTE: it is very important that developer uses object_Shadow_state
73// to disable entry to a window. If you can not enter the object it should
74// be shadowed (disabled). Using a non-zero return to disable entry to an
75// enabled windows should be avoided.
76//
77// It is expected that the external control will want to hook into the
78// following messages already created in this class:
79// External_SetFocus : Most likey assigned to WM_SetFocus
80// External_KillFocus: Most likely assign to WM_KillFocus
81//
82//
83// expected usage:
84//
85// Class MyFancyControl_Mixin is a Mixin
86// Import_Class_Protocol External_Class_Mixin
87// Procedure Define_MyFancyControl_Mixin
88// Set External_Class_Name '?????' To "?????"
89// Set External_Message ?????? To ?????
90// Set External_Message WM_SETFOCUS To External_SetFocus
91// Set External_Message WM_KILLFOCUS To External_KillFocus
92// :
93// end_procedure
94// :
95// Procedure PreInitializeWindow
96// : called before control has been paged
97// End_procedure
98// :
99// Procedure InitializeWindow
100// : called after control has been paged
101// End_procedure
102// End_Class
103//
104// Class dbMyFancyControl is a dbFormExternalControl
105// Import_Class_Protocol MyFancy_control_Mixin
106// Procedure Construct_Object
107// forward send construct_object
108// Send Define_MyFancyControl_Mixin
109// :
110// end_procedure
111// :
112// end_Class
113//
114Use VDFBase.pkg
115
116Class External_Class_Mixin is a Mixin
117 { Visibility=Private }
118 Procedure External_SetFocus
119 integer iFail
120 // if focus is already here then DF knows about the focus
121 // change (it started it) and we need to do nothing. Else,
122 // Windows started the focus change and we need to tell the
123 // df side about it.
124 if (Focus(desktop)<>self) Begin
125 // this should not fail. If the object cannot be activated
126 // then it should be disabled.
127 get msg_Activate to iFail
128 if not iFail ;
129 Send Notify_Focus_Change true
130 end
131 End_Procedure
132
133 { Visibility=Private }
134 Procedure External_KillFocus
135 // this is not getting sent when the external control loses
136 // the focus
137 Send Notify_Focus_Change false
138 End_Procedure
139
140 // Normally this is not used. This is called right before the
141 // windows control is created. Can be used to set windows
142 // styles.
143 { Visibility=Private }
144 Procedure PreInitializeWindow
145 End_Procedure
146
147 // Normally this will get replaced (not augmented) by a mixin at
148 // the same level.
149 { Visibility=Private }
150 Procedure InitializeWindow
151 End_Procedure
152
153 { Visibility=Private }
154 Procedure Page_Object Integer state
155 Integer winhnd
156 Get Window_Handle TO winhnd
157 IF (state AND winhnd=0) Begin
158 Send PreInitializeWindow // if init is required before creating control
159 Forward Send Page_Object state
160 Send InitializeWindow
161 Send Shadow_Display
162 End
163 else ;
164 Forward Send Page_Object state
165 End_Procedure
166
167 // This could be augmented to do whatever is required to make
168 // this control enable
169 { Visibility=Private }
170 Procedure Enable_Window integer iState
171 integer hWnd
172 Get Window_Handle to hWnd
173 If hWnd ;
174 Move (EnableWindow(hWnd,iState)) To hWnd
175 End_procedure
176
177 { MethodType=Event Visibility=Private }
178 Procedure Shadow_Display
179 Send Enable_Window (Not(Object_Shadow_State(Self)))
180 End_Procedure
181
182 // Currently form based classes cancel the set focus message if
183 // there are no form_windows (which there will not be in an
184 // external class). So we force windows to do the focus change. This
185 // behavior may change in the future.
186 //
187 { Visibility=Private }
188 procedure set Focus integer h1 integer h2
189 integer rval
190 Forward Set focus to h1 h2
191 get window_handle to h1
192 Move (SetFocus(h1)) to rval
193 Send Notify_Focus_Change true
194 end_procedure
195
196End_Class
197