Committing in .
[wxWidgets.git] / src / motif / toplevel.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: 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 #if defined(__GNUG__) && !defined(__APPLE__)
21 #pragma implementation "toplevel.h"
22 #endif
23
24 #include "wx/toplevel.h"
25 #include "wx/app.h"
26
27 #ifdef __VMS__
28 #define XtDisplay XTDISPLAY
29 #define XtParent XTPARENT
30 #define XtScreen XTSCREEN
31 #define XtWindow XTWINDOW
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 wxTopLevelWindowMotif::~wxTopLevelWindowMotif()
68 {
69 wxTopLevelWindows.DeleteObject(this);
70
71 if ( (GetWindowStyleFlag() & wxDIALOG_MODAL) != wxDIALOG_MODAL )
72 wxModelessWindows.DeleteObject(this);
73
74 m_icons.m_icons.Empty();
75
76 DestroyChildren();
77
78 // MessageDialog and FileDialog do not have a client widget
79 if( GetClientWidget() )
80 {
81 XtRemoveEventHandler( (Widget)GetClientWidget(),
82 ButtonPressMask | ButtonReleaseMask |
83 PointerMotionMask | KeyPressMask,
84 FALSE,
85 wxTLWEventHandler,
86 (XtPointer)this );
87 }
88
89 DoDestroy();
90
91 SetMainWidget( (WXWidget)0 );
92
93 // If this is the last top-level window, exit.
94 if (wxTheApp && (wxTopLevelWindows.GetCount() == 0))
95 {
96 wxTheApp->SetTopWindow(NULL);
97
98 if (wxTheApp->GetExitOnFrameDelete())
99 {
100 wxTheApp->ExitMainLoop();
101 }
102 }
103 }
104
105 void wxTopLevelWindowMotif::Init()
106 {
107 m_isShown = FALSE;
108 }
109
110 bool wxTopLevelWindowMotif::Create( wxWindow *parent, wxWindowID id,
111 const wxString& title,
112 const wxPoint& pos,
113 const wxSize& size,
114 long style,
115 const wxString& name )
116 {
117 SetName(name);
118 m_windowStyle = style;
119
120 if ( parent )
121 parent->AddChild(this);
122
123 wxTopLevelWindows.Append(this);
124
125 m_windowId = ( id > -1 ) ? id : NewControlId();
126
127 bool retval = DoCreate( parent, id, title, pos, size, style, name );
128
129 if( !retval ) return FALSE;
130
131 // Intercept CLOSE messages from the window manager
132 Widget shell = (Widget)GetShellWidget();
133 Atom WM_DELETE_WINDOW = XmInternAtom( XtDisplay( shell ),
134 "WM_DELETE_WINDOW", False );
135
136 // Remove and add WM_DELETE_WINDOW so ours is only handler
137 // This only appears to be necessary for wxDialog, but does not hurt
138 // for wxFrame
139 XmRemoveWMProtocols( shell, &WM_DELETE_WINDOW, 1 );
140 XmAddWMProtocols( shell, &WM_DELETE_WINDOW, 1 );
141 XmActivateWMProtocol( shell, WM_DELETE_WINDOW );
142
143 // Modified Steve Hammes for Motif 2.0
144 #if (XmREVISION > 1 || XmVERSION > 1)
145 XmAddWMProtocolCallback( shell, WM_DELETE_WINDOW,
146 (XtCallbackProc)wxCloseTLWCallback,
147 (XtPointer)this );
148 #elif XmREVISION == 1
149 XmAddWMProtocolCallback( shell, WM_DELETE_WINDOW,
150 (XtCallbackProc)wxCloseTLWCallback,
151 (caddr_t)this );
152 #else
153 XmAddWMProtocolCallback( shell, WM_DELETE_WINDOW,
154 (void (*)())wxCloseTLWCallback, (caddr_t)this );
155 #endif
156
157 // This patch come from Torsten Liermann lier@lier1.muc.de
158 if( XmIsMotifWMRunning( shell ) )
159 {
160 int decor = 0 ;
161 if( m_windowStyle & wxRESIZE_BORDER )
162 decor |= MWM_DECOR_RESIZEH;
163 if( m_windowStyle & wxSYSTEM_MENU )
164 decor |= MWM_DECOR_MENU;
165 if( ( m_windowStyle & wxCAPTION ) ||
166 ( m_windowStyle & wxTINY_CAPTION_HORIZ ) ||
167 ( m_windowStyle & wxTINY_CAPTION_VERT ) )
168 decor |= MWM_DECOR_TITLE;
169 if( m_windowStyle & wxTHICK_FRAME )
170 decor |= MWM_DECOR_BORDER;
171 if( m_windowStyle & wxMINIMIZE_BOX )
172 decor |= MWM_DECOR_MINIMIZE;
173 if( m_windowStyle & wxMAXIMIZE_BOX )
174 decor |= MWM_DECOR_MAXIMIZE;
175
176 XtVaSetValues( shell,
177 XmNmwmDecorations, decor,
178 NULL );
179 }
180 else
181 {
182 // This allows non-Motif window managers to support at least the
183 // no-decorations case.
184 if( ( m_windowStyle & wxCAPTION ) != wxCAPTION )
185 XtVaSetValues( shell,
186 XmNoverrideRedirect, TRUE,
187 NULL );
188 }
189
190 XtAddEventHandler( (Widget)GetClientWidget(),
191 ButtonPressMask | ButtonReleaseMask |
192 PointerMotionMask | KeyPressMask,
193 FALSE,
194 wxTLWEventHandler,
195 (XtPointer)this );
196
197 return retval;
198 }
199
200 void wxTopLevelWindowMotif::Raise()
201 {
202 Widget top = (Widget) GetTopWidget();
203 Window parent_window = XtWindow( top ),
204 next_parent = XtWindow( top ),
205 root = RootWindowOfScreen( XtScreen( top ) );
206 // search for the parent that is child of ROOT, because the WM may
207 // reparent twice and notify only the next parent (like FVWM)
208 while( next_parent != root )
209 {
210 Window *theChildren;
211 unsigned int n;
212
213 parent_window = next_parent;
214 XQueryTree( XtDisplay( top ), parent_window, &root,
215 &next_parent, &theChildren, &n );
216 XFree( theChildren ); // not needed
217 }
218 XRaiseWindow( XtDisplay( top ), parent_window );
219 }
220
221 void wxTopLevelWindowMotif::Lower()
222 {
223 Widget top = (Widget) GetTopWidget();
224 Window parent_window = XtWindow( top ),
225 next_parent = XtWindow( top ),
226 root = RootWindowOfScreen( XtScreen( top ) );
227 // search for the parent that is child of ROOT, because the WM may
228 // reparent twice and notify only the next parent (like FVWM)
229 while( next_parent != root )
230 {
231 Window *theChildren;
232 unsigned int n;
233
234 parent_window = next_parent;
235 XQueryTree( XtDisplay( top ), parent_window, &root,
236 &next_parent, &theChildren, &n );
237 XFree( theChildren ); // not needed
238 }
239 XLowerWindow( XtDisplay( top ), parent_window );
240 }
241
242 static inline Widget GetShell( const wxTopLevelWindowMotif* tlw )
243 {
244 Widget main = (Widget) tlw->GetMainWidget();
245 if( !main ) return (Widget) NULL;
246
247 return XtParent( main );
248 }
249
250 WXWidget wxTopLevelWindowMotif::GetShellWidget() const
251 {
252 return (WXWidget) GetShell( this );
253 }
254
255 bool wxTopLevelWindowMotif::ShowFullScreen( bool show,
256 long style )
257 {
258 // TODO, see wxGTK
259 return FALSE;
260 }
261
262 bool wxTopLevelWindowMotif::IsFullScreen() const
263 {
264 // TODO, see wxGTK
265 return FALSE;
266 }
267
268 void wxTopLevelWindowMotif::Restore()
269 {
270 Widget shell = GetShell( this );
271
272 if( shell )
273 XtVaSetValues( shell,
274 XmNiconic, FALSE,
275 NULL );
276 }
277
278 void wxTopLevelWindowMotif::Iconize( bool iconize )
279 {
280 Widget shell = GetShell( this );
281 if( !shell ) return;
282
283 if( !iconize )
284 Show( TRUE );
285
286 XtVaSetValues( shell,
287 XmNiconic, (Boolean)iconize,
288 NULL );
289 }
290
291 bool wxTopLevelWindowMotif::IsIconized() const
292 {
293 Widget shell = GetShell( this );
294
295 if( !shell )
296 return FALSE;
297
298 Boolean iconic;
299 XtVaGetValues( shell,
300 XmNiconic, &iconic,
301 NULL );
302
303 return iconic;
304 }
305
306 void wxTopLevelWindowMotif::Maximize( bool maximize )
307 {
308 Show( TRUE );
309
310 if( maximize )
311 Restore();
312 }
313
314 bool wxTopLevelWindowMotif::IsMaximized() const
315 {
316 return FALSE;
317 }
318
319 // ---------------------------------------------------------------------------
320 // Callback definition
321 // ---------------------------------------------------------------------------
322
323 // Handle a close event from the window manager
324 static void wxCloseTLWCallback( Widget WXUNUSED(widget), XtPointer client_data,
325 XmAnyCallbackStruct *WXUNUSED(cbs) )
326 {
327 wxTopLevelWindowMotif* tlw = (wxTopLevelWindowMotif*)client_data;
328 wxCloseEvent closeEvent( wxEVT_CLOSE_WINDOW, tlw->GetId() );
329 closeEvent.SetEventObject( tlw );
330
331 // May delete the dialog (with delayed deletion)
332 tlw->GetEventHandler()->ProcessEvent(closeEvent);
333 }
334
335 void wxTLWEventHandler( Widget wid,
336 XtPointer WXUNUSED(client_data),
337 XEvent* event,
338 Boolean* continueToDispatch)
339 {
340 wxTopLevelWindowMotif* tlw =
341 (wxTopLevelWindowMotif*)wxGetWindowFromTable( wid );
342
343 if( tlw )
344 {
345 wxMouseEvent wxevent( wxEVT_NULL );
346
347 if( wxTranslateMouseEvent( wxevent, tlw, wid, event ) )
348 {
349 wxevent.SetEventObject( tlw );
350 wxevent.SetId( tlw->GetId() );
351 tlw->GetEventHandler()->ProcessEvent( wxevent );
352 }
353 else
354 {
355 // An attempt to implement OnCharHook by calling OnCharHook first;
356 // if this returns TRUE, set continueToDispatch to False
357 // (don't continue processing).
358 // Otherwise set it to True and call OnChar.
359 wxKeyEvent keyEvent( wxEVT_CHAR );
360 if( wxTranslateKeyEvent( keyEvent, tlw, wid, event ))
361 {
362 keyEvent.SetEventObject( tlw );
363 keyEvent.SetId( tlw->GetId() );
364 keyEvent.SetEventType( wxEVT_CHAR_HOOK );
365 if( tlw->GetEventHandler()->ProcessEvent( keyEvent ) )
366 {
367 *continueToDispatch = False;
368 return;
369 }
370 else
371 {
372 // For simplicity, OnKeyDown is the same as OnChar
373 // TODO: filter modifier key presses from OnChar
374 keyEvent.SetEventType( wxEVT_KEY_DOWN );
375
376 // Only process OnChar if OnKeyDown didn't swallow it
377 if( !tlw->GetEventHandler()->ProcessEvent( keyEvent ) )
378 {
379 keyEvent.SetEventType( wxEVT_CHAR );
380 tlw->GetEventHandler()->ProcessEvent( keyEvent );
381 }
382 }
383 }
384 }
385 }
386
387 *continueToDispatch = True;
388 }
389