1 /********************************************************************************
2 * *
3 * S h e l l W i n d o w O b j e c t *
4 * *
5 *********************************************************************************
6 * Copyright (C) 1997,2020 by Jeroen van der Zijp. All Rights Reserved. *
7 *********************************************************************************
8 * This library is free software; you can redistribute it and/or modify *
9 * it under the terms of the GNU Lesser General Public License as published by *
10 * the Free Software Foundation; either version 3 of the License, or *
11 * (at your option) any later version. *
12 * *
13 * This library is distributed in the hope that it will be useful, *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16 * GNU Lesser General Public License for more details. *
17 * *
18 * You should have received a copy of the GNU Lesser General Public License *
19 * along with this program. If not, see <http://www.gnu.org/licenses/> *
20 ********************************************************************************/
21 #include "xincs.h"
22 #include "fxver.h"
23 #include "fxdefs.h"
24 #include "fxmath.h"
25 #include "fxkeys.h"
26 #include "FXArray.h"
27 #include "FXHash.h"
28 #include "FXMutex.h"
29 #include "FXStream.h"
30 #include "FXString.h"
31 #include "FXSize.h"
32 #include "FXPoint.h"
33 #include "FXRectangle.h"
34 #include "FXStringDictionary.h"
35 #include "FXSettings.h"
36 #include "FXRegistry.h"
37 #include "FXAccelTable.h"
38 #include "FXEvent.h"
39 #include "FXWindow.h"
40 #include "FXApp.h"
41 #include "FXShell.h"
42
43
44 /*
45 Notes:
46 - FXShell handles keys to implement focus change messages.
47 - The initial size should probably be determined not in create(), but in show().
48 - Note that Shell is base class for transient ``popup'' override-redirect windows.
49 For top level windows, we should use size hints rather than force the size.
50 */
51
52 using namespace FX;
53
54 /*******************************************************************************/
55
56 namespace FX {
57
58 // Map
59 FXDEFMAP(FXShell) FXShellMap[]={
60 FXMAPFUNC(SEL_CONFIGURE,0,FXShell::onConfigure),
61 FXMAPFUNC(SEL_KEYPRESS,0,FXShell::onKeyPress),
62 FXMAPFUNC(SEL_KEYRELEASE,0,FXShell::onKeyRelease),
63 FXMAPFUNC(SEL_FOCUS_NEXT,0,FXShell::onFocusNext),
64 FXMAPFUNC(SEL_FOCUS_PREV,0,FXShell::onFocusPrev),
65 FXMAPFUNC(SEL_CHORE,FXShell::ID_LAYOUT,FXShell::onLayout),
66 };
67
68
69 // Object implementation
FXIMPLEMENT(FXShell,FXComposite,FXShellMap,ARRAYNUMBER (FXShellMap))70 FXIMPLEMENT(FXShell,FXComposite,FXShellMap,ARRAYNUMBER(FXShellMap))
71
72
73 // Create a toplevel window
74 FXShell::FXShell(FXApp* a,FXuint opts,FXint x,FXint y,FXint w,FXint h):FXComposite(a,NULL,opts,x,y,w,h){
75 }
76
77
78 // Create a toplevel window
FXShell(FXWindow * own,FXuint opts,FXint x,FXint y,FXint w,FXint h)79 FXShell::FXShell(FXWindow* own,FXuint opts,FXint x,FXint y,FXint w,FXint h):FXComposite(own->getApp(),own,opts,x,y,w,h){
80 }
81
82
83 // Create X window
create()84 void FXShell::create(){
85 FXint w,h;
86
87 // Create this widget and all of its children
88 FXComposite::create();
89
90 // Adjust size if necessary
91 w=(1<width) ? width : getDefaultWidth();
92 h=(1<height) ? height : getDefaultHeight();
93
94 // Resize this widget
95 resize(w,h);
96 }
97
98
99 // Schedule layout to be peformed during idle time
recalc()100 void FXShell::recalc(){
101 getApp()->addChore(this,ID_LAYOUT);
102 flags|=FLAG_DIRTY;
103 }
104
105
106 // Shell into the focus chain
setFocus()107 void FXShell::setFocus(){
108 flags|=FLAG_HELP;
109 }
110
111
112 // Shell out of focus chain
killFocus()113 void FXShell::killFocus(){
114 if(getFocus()) getFocus()->killFocus();
115 flags&=~FLAG_HELP;
116 flags|=FLAG_UPDATE;
117 }
118
119
120 // Perform layout; return 0 because no GUI update is needed
onLayout(FXObject *,FXSelector,void *)121 long FXShell::onLayout(FXObject*,FXSelector,void*){
122 layout();
123 return 0;
124 }
125
126
127 // Handle configure notify
onConfigure(FXObject * sender,FXSelector sel,void * ptr)128 long FXShell::onConfigure(FXObject* sender,FXSelector sel,void* ptr){
129 FXEvent *ev=(FXEvent*)ptr;
130 FXComposite::onConfigure(sender,sel,ptr);
131 xpos=ev->rect.x;
132 ypos=ev->rect.y;
133 if((ev->rect.w!=width) || (ev->rect.h!=height)){
134 width=ev->rect.w; // Record new size
135 height=ev->rect.h;
136 // Delayed layout optimization. The delayed layout optimization
137 // currently only works on UNIX. On Windows, the program enters
138 // a modal loop during a window-resize operation. During this
139 // modal loop, which is somewhere inside WIN32 code, we are completely
140 // deaf to other event sources such as timers, chores, file i/o, and
141 // are unable to perform idle processing. So the chore we would set
142 // in recalc() would never fire until we're all done with the resizing.
143 // We'd love to have a fix for this, but it seems difficult because of
144 // the need to pass "non-client" events over to the DefWindowProc...
145 #ifdef WIN32
146 layout(); // On Windows, we are in a modal loop and we have to force it
147 #else
148 recalc(); // On UNIX, we process idle messages during a resize
149 #endif
150 }
151 return 1;
152 }
153
154
155 // Focus moved to next
onFocusNext(FXObject * sender,FXSelector,void * ptr)156 long FXShell::onFocusNext(FXObject* sender,FXSelector,void* ptr){
157 FXWindow *child;
158 if(getFocus()){
159 child=getFocus()->getNext();
160 while(child){
161 if(child->shown()){
162 if(child->handle(this,FXSEL(SEL_FOCUS_SELF,0),ptr)) return 1;
163 if(child->handle(sender,FXSEL(SEL_FOCUS_NEXT,0),ptr)) return 1;
164 }
165 child=child->getNext();
166 }
167 getFocus()->killFocus();
168 }
169 child=getFirst();
170 while(child){
171 if(child->shown()){
172 if(child->handle(this,FXSEL(SEL_FOCUS_SELF,0),ptr)) return 1;
173 if(child->handle(sender,FXSEL(SEL_FOCUS_NEXT,0),ptr)) return 1;
174 }
175 child=child->getNext();
176 }
177 return 0;
178 }
179
180
181 // Focus moved to previous
onFocusPrev(FXObject * sender,FXSelector,void * ptr)182 long FXShell::onFocusPrev(FXObject* sender,FXSelector,void* ptr){
183 FXWindow *child;
184 if(getFocus()){
185 child=getFocus()->getPrev();
186 while(child){
187 if(child->shown()){
188 if(child->handle(this,FXSEL(SEL_FOCUS_SELF,0),ptr)) return 1;
189 if(child->handle(sender,FXSEL(SEL_FOCUS_PREV,0),ptr)) return 1;
190 }
191 child=child->getPrev();
192 }
193 getFocus()->killFocus();
194 }
195 child=getLast();
196 while(child){
197 if(child->shown()){
198 if(child->handle(this,FXSEL(SEL_FOCUS_SELF,0),ptr)) return 1;
199 if(child->handle(sender,FXSEL(SEL_FOCUS_PREV,0),ptr)) return 1;
200 }
201 child=child->getPrev();
202 }
203 return 0;
204 }
205
206
207 // Keyboard press
onKeyPress(FXObject * sender,FXSelector sel,void * ptr)208 long FXShell::onKeyPress(FXObject* sender,FXSelector sel,void* ptr){
209
210 // Try to handle normally
211 if(FXComposite::onKeyPress(sender,sel,ptr)) return 1;
212
213 // If not handled yet, try the default button
214 if(((FXEvent*)ptr)->code==KEY_Return || ((FXEvent*)ptr)->code==KEY_KP_Enter){
215
216 // Find default widget
217 FXWindow* def=findDefault();
218
219 // Handle default key
220 if(def && def->handle(sender,sel,ptr)) return 1;
221 }
222 return 0;
223 }
224
225
226 // Keyboard release
onKeyRelease(FXObject * sender,FXSelector sel,void * ptr)227 long FXShell::onKeyRelease(FXObject* sender,FXSelector sel,void* ptr){
228
229 // Try to handle normally
230 if(FXComposite::onKeyRelease(sender,sel,ptr)) return 1;
231
232 // If not handled yet, try the default button
233 if(((FXEvent*)ptr)->code==KEY_Return || ((FXEvent*)ptr)->code==KEY_KP_Enter){
234
235 // Find default widget
236 FXWindow* def=findDefault();
237
238 // Handle default key
239 if(def && def->handle(sender,sel,ptr)) return 1;
240 }
241 return 0;
242 }
243
244
245 // Destruct
~FXShell()246 FXShell::~FXShell(){
247 getApp()->removeChore(this,ID_LAYOUT);
248 }
249
250 }
251
252
253