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