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