Add wxTEST_DIALOG for testing of modal dialogs.
[wxWidgets.git] / src / motif / toplevel.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/motif/toplevel.cpp
3 // Purpose: wxTopLevelWindow Motif implementation
4 // Author: Mattia Barbon
5 // Modified by:
6 // Created: 12/10/2002
7 // RCS-ID: $Id$
8 // Copyright: (c) Mattia Barbon
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 // For compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
22
23 #include "wx/toplevel.h"
24 #include "wx/settings.h"
25 #include "wx/app.h"
26
27 #ifndef WX_PRECOMP
28 #include "wx/app.h"
29 #endif
30
31 #ifdef __VMS__
32 #pragma message disable nosimpint
33 #endif
34
35 #include <Xm/Xm.h>
36 #include <X11/Shell.h>
37 #include <X11/Core.h>
38 #if XmVersion >= 1002
39 #include <Xm/XmAll.h>
40 #else
41 #include <Xm/Frame.h>
42 #endif
43
44 #ifdef __VMS__
45 #pragma message enable nosimpint
46 #endif
47
48 #include "wx/motif/private.h"
49
50 wxList wxModelessWindows; // Frames and modeless dialogs
51
52 // ---------------------------------------------------------------------------
53 // Callbacks
54 // ---------------------------------------------------------------------------
55
56 static void wxCloseTLWCallback( Widget widget, XtPointer client_data,
57 XmAnyCallbackStruct *cbs );
58 static void wxTLWEventHandler( Widget wid,
59 XtPointer client_data,
60 XEvent* event,
61 Boolean *continueToDispatch );
62
63 // ===========================================================================
64 // wxTopLevelWindowMotif implementation
65 // ===========================================================================
66
67 void wxTopLevelWindowMotif::PreDestroy()
68 {
69 wxModelessWindows.DeleteObject(this);
70
71 DestroyChildren();
72
73 // MessageDialog and FileDialog do not have a client widget
74 if( GetClientWidget() )
75 {
76 XtRemoveEventHandler( (Widget)GetClientWidget(),
77 ButtonPressMask | ButtonReleaseMask |
78 PointerMotionMask | KeyPressMask,
79 False,
80 wxTLWEventHandler,
81 (XtPointer)this );
82 }
83 }
84
85 wxTopLevelWindowMotif::~wxTopLevelWindowMotif()
86 {
87 SetMainWidget( (WXWidget)0 );
88 }
89
90 void wxTopLevelWindowMotif::Init()
91 {
92 m_isShown = false;
93 }
94
95 bool wxTopLevelWindowMotif::Create( wxWindow *parent, wxWindowID id,
96 const wxString& title,
97 const wxPoint& pos,
98 const wxSize& size,
99 long style,
100 const wxString& name )
101 {
102 SetName(name);
103 m_windowStyle = style;
104
105 if ( parent )
106 parent->AddChild(this);
107
108 wxTopLevelWindows.Append(this);
109
110 m_windowId = ( id > -1 ) ? id : NewControlId();
111 // MBN: More backward compatible, but uglier
112 m_font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
113 m_inheritFont = true;
114
115 bool retval = XmDoCreateTLW( parent, id, title, pos, size, style, name );
116
117 if( !retval ) return false;
118
119 // Intercept CLOSE messages from the window manager
120 Widget shell = (Widget)GetShellWidget();
121 Atom WM_DELETE_WINDOW = XmInternAtom( XtDisplay( shell ),
122 "WM_DELETE_WINDOW", False );
123
124 // Remove and add WM_DELETE_WINDOW so ours is only handler
125 // This only appears to be necessary for wxDialog, but does not hurt
126 // for wxFrame
127 XmRemoveWMProtocols( shell, &WM_DELETE_WINDOW, 1 );
128 XmAddWMProtocols( shell, &WM_DELETE_WINDOW, 1 );
129 XmActivateWMProtocol( shell, WM_DELETE_WINDOW );
130
131 // Modified Steve Hammes for Motif 2.0
132 #if (XmREVISION > 1 || XmVERSION > 1)
133 XmAddWMProtocolCallback( shell, WM_DELETE_WINDOW,
134 (XtCallbackProc)wxCloseTLWCallback,
135 (XtPointer)this );
136 #elif XmREVISION == 1
137 XmAddWMProtocolCallback( shell, WM_DELETE_WINDOW,
138 (XtCallbackProc)wxCloseTLWCallback,
139 (caddr_t)this );
140 #else
141 XmAddWMProtocolCallback( shell, WM_DELETE_WINDOW,
142 (void (*)())wxCloseTLWCallback, (caddr_t)this );
143 #endif
144
145 // This patch come from Torsten Liermann lier@lier1.muc.de
146 if( XmIsMotifWMRunning( shell ) )
147 {
148 int decor = 0 ;
149 if( !(m_windowStyle & wxNO_BORDER) )
150 decor |= MWM_DECOR_BORDER;
151 if( m_windowStyle & wxRESIZE_BORDER )
152 decor |= MWM_DECOR_RESIZEH;
153 if( m_windowStyle & wxSYSTEM_MENU )
154 decor |= MWM_DECOR_MENU;
155 if( ( m_windowStyle & wxCAPTION ) ||
156 ( m_windowStyle & wxTINY_CAPTION) )
157 decor |= MWM_DECOR_TITLE;
158 if( m_windowStyle & wxRESIZE_BORDER )
159 decor |= MWM_DECOR_BORDER;
160 if( m_windowStyle & wxMINIMIZE_BOX )
161 decor |= MWM_DECOR_MINIMIZE;
162 if( m_windowStyle & wxMAXIMIZE_BOX )
163 decor |= MWM_DECOR_MAXIMIZE;
164
165 XtVaSetValues( shell,
166 XmNmwmDecorations, decor,
167 NULL );
168 }
169 else
170 {
171 // This allows non-Motif window managers to support at least the
172 // no-decorations case.
173 if( ( m_windowStyle & wxCAPTION ) != wxCAPTION )
174 XtVaSetValues( shell,
175 XmNoverrideRedirect, True,
176 NULL );
177 }
178
179 XtAddEventHandler( (Widget)GetClientWidget(),
180 ButtonPressMask | ButtonReleaseMask |
181 PointerMotionMask | KeyPressMask,
182 False,
183 wxTLWEventHandler,
184 (XtPointer)this );
185
186 return retval;
187 }
188
189 void wxTopLevelWindowMotif::DoGetPosition(int *x, int *y) const
190 {
191 Widget top = (Widget) GetTopWidget();
192 Window parent_window = XtWindow((Widget) top),
193 next_parent = XtWindow((Widget) top),
194 root = RootWindowOfScreen(XtScreen((Widget) top));
195
196 // search for the parent that is child of ROOT, because the WM may
197 // reparent twice and notify only the next parent (like FVWM)
198 while (next_parent != root) {
199 Window *theChildren; unsigned int n;
200 parent_window = next_parent;
201 XQueryTree(XtDisplay((Widget) top), parent_window, &root,
202 &next_parent, &theChildren, &n);
203 XFree(theChildren); // not needed
204 }
205 int xx, yy; unsigned int dummy;
206 XGetGeometry(XtDisplay((Widget) top), parent_window, &root,
207 &xx, &yy, &dummy, &dummy, &dummy, &dummy);
208 if (x) *x = xx;
209 if (y) *y = yy;
210 }
211
212 void wxTopLevelWindowMotif::Raise()
213 {
214 Widget top = (Widget) GetTopWidget();
215 Window parent_window = XtWindow( top ),
216 next_parent = XtWindow( top ),
217 root = RootWindowOfScreen( XtScreen( top ) );
218 // search for the parent that is child of ROOT, because the WM may
219 // reparent twice and notify only the next parent (like FVWM)
220 while( next_parent != root )
221 {
222 Window *theChildren;
223 unsigned int n;
224
225 parent_window = next_parent;
226 XQueryTree( XtDisplay( top ), parent_window, &root,
227 &next_parent, &theChildren, &n );
228 XFree( theChildren ); // not needed
229 }
230 XRaiseWindow( XtDisplay( top ), parent_window );
231 }
232
233 void wxTopLevelWindowMotif::Lower()
234 {
235 Widget top = (Widget) GetTopWidget();
236 Window parent_window = XtWindow( top ),
237 next_parent = XtWindow( top ),
238 root = RootWindowOfScreen( XtScreen( top ) );
239 // search for the parent that is child of ROOT, because the WM may
240 // reparent twice and notify only the next parent (like FVWM)
241 while( next_parent != root )
242 {
243 Window *theChildren;
244 unsigned int n;
245
246 parent_window = next_parent;
247 XQueryTree( XtDisplay( top ), parent_window, &root,
248 &next_parent, &theChildren, &n );
249 XFree( theChildren ); // not needed
250 }
251 XLowerWindow( XtDisplay( top ), parent_window );
252 }
253
254 static inline Widget GetShell( const wxTopLevelWindowMotif* tlw )
255 {
256 Widget main = (Widget) tlw->GetMainWidget();
257 if( !main ) return (Widget) NULL;
258
259 return XtParent( main );
260 }
261
262 WXWidget wxTopLevelWindowMotif::GetShellWidget() const
263 {
264 return (WXWidget) GetShell( this );
265 }
266
267 bool wxTopLevelWindowMotif::ShowFullScreen( bool WXUNUSED(show),
268 long WXUNUSED(style) )
269 {
270 // TODO, see wxGTK
271 return false;
272 }
273
274 bool wxTopLevelWindowMotif::IsFullScreen() const
275 {
276 // TODO, see wxGTK
277 return false;
278 }
279
280 void wxTopLevelWindowMotif::Restore()
281 {
282 Widget shell = GetShell( this );
283
284 if( shell )
285 XtVaSetValues( shell,
286 XmNiconic, False,
287 NULL );
288 }
289
290 void wxTopLevelWindowMotif::Iconize( bool iconize )
291 {
292 Widget shell = GetShell( this );
293 if( !shell ) return;
294
295 if( !iconize )
296 Show( true );
297
298 XtVaSetValues( shell,
299 XmNiconic, (Boolean)iconize,
300 NULL );
301 }
302
303 bool wxTopLevelWindowMotif::IsIconized() const
304 {
305 Widget shell = GetShell( this );
306
307 if( !shell )
308 return false;
309
310 Boolean iconic;
311 XtVaGetValues( shell,
312 XmNiconic, &iconic,
313 NULL );
314
315 return (iconic == True);
316 }
317
318 void wxTopLevelWindowMotif::Maximize( bool maximize )
319 {
320 Show( true );
321
322 if( maximize )
323 Restore();
324 }
325
326 bool wxTopLevelWindowMotif::IsMaximized() const
327 {
328 return false;
329 }
330
331 void wxTopLevelWindowMotif::DoSetSizeHints( int minW, int minH,
332 int maxW, int maxH,
333 int incW, int incH )
334 {
335 wxTopLevelWindowBase::DoSetSizeHints( minW, minH, maxW, maxH, incW, incH );
336
337 int count = 0;
338 Arg args[6];
339
340 if( minW > -1 ) { XtSetArg( args[count], XmNminWidth, minW ); ++count; }
341 if( minH > -1 ) { XtSetArg( args[count], XmNminHeight, minH ); ++count; }
342 if( maxW > -1 ) { XtSetArg( args[count], XmNmaxWidth, maxW ); ++count; }
343 if( maxH > -1 ) { XtSetArg( args[count], XmNmaxHeight, maxH ); ++count; }
344 if( incW > -1 ) { XtSetArg( args[count], XmNwidthInc, incW ); ++count; }
345 if( incH > -1 ) { XtSetArg( args[count], XmNheightInc, incH ); ++count; }
346
347 XtSetValues( (Widget)GetShellWidget(), args, count );
348 }
349
350 bool wxTopLevelWindowMotif::SetShape( const wxRegion& region )
351 {
352 return wxDoSetShape( (Display*)GetXDisplay(),
353 XtWindow( (Widget)GetShellWidget() ),
354 region );
355 }
356
357 // ---------------------------------------------------------------------------
358 // Callback definition
359 // ---------------------------------------------------------------------------
360
361 // Handle a close event from the window manager
362 static void wxCloseTLWCallback( Widget WXUNUSED(widget), XtPointer client_data,
363 XmAnyCallbackStruct *WXUNUSED(cbs) )
364 {
365 wxTopLevelWindowMotif* tlw = (wxTopLevelWindowMotif*)client_data;
366 wxCloseEvent closeEvent( wxEVT_CLOSE_WINDOW, tlw->GetId() );
367 closeEvent.SetEventObject( tlw );
368
369 // May delete the dialog (with delayed deletion)
370 tlw->HandleWindowEvent(closeEvent);
371 }
372
373 void wxTLWEventHandler( Widget wid,
374 XtPointer WXUNUSED(client_data),
375 XEvent* event,
376 Boolean* continueToDispatch)
377 {
378 wxTopLevelWindowMotif* tlw =
379 (wxTopLevelWindowMotif*)wxGetWindowFromTable( wid );
380
381 if( tlw )
382 {
383 wxMouseEvent wxevent( wxEVT_NULL );
384
385 if( wxTranslateMouseEvent( wxevent, tlw, wid, event ) )
386 {
387 wxevent.SetEventObject( tlw );
388 wxevent.SetId( tlw->GetId() );
389 tlw->HandleWindowEvent( wxevent );
390 }
391 else
392 {
393 // An attempt to implement OnCharHook by calling OnCharHook first;
394 // if this returns true, set continueToDispatch to False
395 // (don't continue processing).
396 // Otherwise set it to True and call OnChar.
397 wxKeyEvent keyEvent( wxEVT_CHAR );
398 if( wxTranslateKeyEvent( keyEvent, tlw, wid, event ))
399 {
400 keyEvent.SetEventObject( tlw );
401 keyEvent.SetId( tlw->GetId() );
402 keyEvent.SetEventType( wxEVT_CHAR_HOOK );
403 if( tlw->HandleWindowEvent( keyEvent ) )
404 {
405 *continueToDispatch = False;
406 return;
407 }
408 else
409 {
410 // For simplicity, OnKeyDown is the same as OnChar
411 // TODO: filter modifier key presses from OnChar
412 keyEvent.SetEventType( wxEVT_KEY_DOWN );
413
414 // Only process OnChar if OnKeyDown didn't swallow it
415 if( !tlw->HandleWindowEvent( keyEvent ) )
416 {
417 keyEvent.SetEventType( wxEVT_CHAR );
418 tlw->HandleWindowEvent( keyEvent );
419 }
420 }
421 }
422 }
423 }
424
425 *continueToDispatch = True;
426 }