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