]> git.saurik.com Git - wxWidgets.git/blame - src/motif/toplevel.cpp
fixing focus, fixes #11911
[wxWidgets.git] / src / motif / toplevel.cpp
CommitLineData
0de6dfa7 1/////////////////////////////////////////////////////////////////////////////
355b4d3d 2// Name: src/motif/toplevel.cpp
0de6dfa7
MB
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
65571936 9// Licence: wxWindows licence
0de6dfa7
MB
10/////////////////////////////////////////////////////////////////////////////
11
12// ============================================================================
13// declarations
14// ============================================================================
15
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
19
1248b41f
MB
20// For compilers that support precompilation, includes "wx.h".
21#include "wx/wxprec.h"
22
0de6dfa7 23#include "wx/toplevel.h"
105fbe1f
MB
24#include "wx/settings.h"
25#include "wx/app.h"
670f9935
WS
26
27#ifndef WX_PRECOMP
28 #include "wx/app.h"
29#endif
0de6dfa7
MB
30
31#ifdef __VMS__
e004299a 32#pragma message disable nosimpint
0de6dfa7
MB
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
50wxList wxModelessWindows; // Frames and modeless dialogs
51
52// ---------------------------------------------------------------------------
53// Callbacks
54// ---------------------------------------------------------------------------
55
56static void wxCloseTLWCallback( Widget widget, XtPointer client_data,
57 XmAnyCallbackStruct *cbs );
58static void wxTLWEventHandler( Widget wid,
59 XtPointer client_data,
60 XEvent* event,
61 Boolean *continueToDispatch );
62
63// ===========================================================================
64// wxTopLevelWindowMotif implementation
65// ===========================================================================
66
2187eef5 67void wxTopLevelWindowMotif::PreDestroy()
0de6dfa7 68{
31df756d 69 wxModelessWindows.DeleteObject(this);
0de6dfa7 70
0de6dfa7
MB
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,
96be256b 79 False,
0de6dfa7
MB
80 wxTLWEventHandler,
81 (XtPointer)this );
82 }
2187eef5 83}
0de6dfa7 84
2187eef5
MB
85wxTopLevelWindowMotif::~wxTopLevelWindowMotif()
86{
0de6dfa7 87 SetMainWidget( (WXWidget)0 );
0de6dfa7
MB
88}
89
90void wxTopLevelWindowMotif::Init()
91{
96be256b 92 m_isShown = false;
0de6dfa7
MB
93}
94
95bool 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);
f58585c0 107
0de6dfa7
MB
108 wxTopLevelWindows.Append(this);
109
110 m_windowId = ( id > -1 ) ? id : NewControlId();
105fbe1f
MB
111 // MBN: More backward compatible, but uglier
112 m_font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
113 m_inheritFont = true;
0de6dfa7 114
02bcd285 115 bool retval = XmDoCreateTLW( parent, id, title, pos, size, style, name );
0de6dfa7 116
96be256b 117 if( !retval ) return false;
0de6dfa7
MB
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,
f58585c0 134 (XtCallbackProc)wxCloseTLWCallback,
0de6dfa7
MB
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 ;
8b7b0d67
MB
149 if( !(m_windowStyle & wxNO_BORDER) )
150 decor |= MWM_DECOR_BORDER;
0de6dfa7
MB
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_HORIZ ) ||
157 ( m_windowStyle & wxTINY_CAPTION_VERT ) )
158 decor |= MWM_DECOR_TITLE;
1c067fe3 159 if( m_windowStyle & wxRESIZE_BORDER )
0de6dfa7
MB
160 decor |= MWM_DECOR_BORDER;
161 if( m_windowStyle & wxMINIMIZE_BOX )
162 decor |= MWM_DECOR_MINIMIZE;
163 if( m_windowStyle & wxMAXIMIZE_BOX )
164 decor |= MWM_DECOR_MAXIMIZE;
165
166 XtVaSetValues( shell,
167 XmNmwmDecorations, decor,
168 NULL );
169 }
170 else
171 {
172 // This allows non-Motif window managers to support at least the
173 // no-decorations case.
174 if( ( m_windowStyle & wxCAPTION ) != wxCAPTION )
175 XtVaSetValues( shell,
96be256b 176 XmNoverrideRedirect, True,
0de6dfa7
MB
177 NULL );
178 }
179
180 XtAddEventHandler( (Widget)GetClientWidget(),
f58585c0 181 ButtonPressMask | ButtonReleaseMask |
0de6dfa7 182 PointerMotionMask | KeyPressMask,
96be256b 183 False,
0de6dfa7
MB
184 wxTLWEventHandler,
185 (XtPointer)this );
186
187 return retval;
188}
189
dad6a47e
MB
190void wxTopLevelWindowMotif::DoGetPosition(int *x, int *y) const
191{
192 Widget top = (Widget) GetTopWidget();
193 Window parent_window = XtWindow((Widget) top),
194 next_parent = XtWindow((Widget) top),
195 root = RootWindowOfScreen(XtScreen((Widget) top));
196
197 // search for the parent that is child of ROOT, because the WM may
198 // reparent twice and notify only the next parent (like FVWM)
199 while (next_parent != root) {
200 Window *theChildren; unsigned int n;
201 parent_window = next_parent;
202 XQueryTree(XtDisplay((Widget) top), parent_window, &root,
203 &next_parent, &theChildren, &n);
204 XFree(theChildren); // not needed
205 }
206 int xx, yy; unsigned int dummy;
207 XGetGeometry(XtDisplay((Widget) top), parent_window, &root,
208 &xx, &yy, &dummy, &dummy, &dummy, &dummy);
209 if (x) *x = xx;
210 if (y) *y = yy;
211}
212
0de6dfa7
MB
213void wxTopLevelWindowMotif::Raise()
214{
215 Widget top = (Widget) GetTopWidget();
216 Window parent_window = XtWindow( top ),
217 next_parent = XtWindow( top ),
218 root = RootWindowOfScreen( XtScreen( top ) );
219 // search for the parent that is child of ROOT, because the WM may
220 // reparent twice and notify only the next parent (like FVWM)
221 while( next_parent != root )
222 {
223 Window *theChildren;
224 unsigned int n;
225
226 parent_window = next_parent;
227 XQueryTree( XtDisplay( top ), parent_window, &root,
228 &next_parent, &theChildren, &n );
229 XFree( theChildren ); // not needed
230 }
231 XRaiseWindow( XtDisplay( top ), parent_window );
232}
233
234void wxTopLevelWindowMotif::Lower()
235{
236 Widget top = (Widget) GetTopWidget();
237 Window parent_window = XtWindow( top ),
238 next_parent = XtWindow( top ),
239 root = RootWindowOfScreen( XtScreen( top ) );
240 // search for the parent that is child of ROOT, because the WM may
241 // reparent twice and notify only the next parent (like FVWM)
242 while( next_parent != root )
243 {
244 Window *theChildren;
245 unsigned int n;
246
247 parent_window = next_parent;
248 XQueryTree( XtDisplay( top ), parent_window, &root,
249 &next_parent, &theChildren, &n );
250 XFree( theChildren ); // not needed
251 }
252 XLowerWindow( XtDisplay( top ), parent_window );
253}
254
255static inline Widget GetShell( const wxTopLevelWindowMotif* tlw )
256{
257 Widget main = (Widget) tlw->GetMainWidget();
258 if( !main ) return (Widget) NULL;
259
260 return XtParent( main );
261}
262
263WXWidget wxTopLevelWindowMotif::GetShellWidget() const
264{
265 return (WXWidget) GetShell( this );
266}
267
355b4d3d
WS
268bool wxTopLevelWindowMotif::ShowFullScreen( bool WXUNUSED(show),
269 long WXUNUSED(style) )
0de6dfa7
MB
270{
271 // TODO, see wxGTK
96be256b 272 return false;
0de6dfa7
MB
273}
274
275bool wxTopLevelWindowMotif::IsFullScreen() const
276{
277 // TODO, see wxGTK
96be256b 278 return false;
0de6dfa7
MB
279}
280
281void wxTopLevelWindowMotif::Restore()
282{
283 Widget shell = GetShell( this );
284
285 if( shell )
286 XtVaSetValues( shell,
96be256b 287 XmNiconic, False,
0de6dfa7
MB
288 NULL );
289}
290
0ec6fd04 291void wxTopLevelWindowMotif::Iconize( bool iconize )
0de6dfa7
MB
292{
293 Widget shell = GetShell( this );
294 if( !shell ) return;
295
296 if( !iconize )
96be256b 297 Show( true );
0de6dfa7
MB
298
299 XtVaSetValues( shell,
300 XmNiconic, (Boolean)iconize,
301 NULL );
302}
303
304bool wxTopLevelWindowMotif::IsIconized() const
305{
306 Widget shell = GetShell( this );
307
308 if( !shell )
96be256b 309 return false;
0de6dfa7
MB
310
311 Boolean iconic;
312 XtVaGetValues( shell,
313 XmNiconic, &iconic,
314 NULL );
315
355b4d3d 316 return (iconic == True);
0de6dfa7
MB
317}
318
0ec6fd04 319void wxTopLevelWindowMotif::Maximize( bool maximize )
0de6dfa7 320{
96be256b 321 Show( true );
0de6dfa7
MB
322
323 if( maximize )
324 Restore();
325}
326
327bool wxTopLevelWindowMotif::IsMaximized() const
328{
96be256b 329 return false;
0de6dfa7
MB
330}
331
024f89f9
VS
332void wxTopLevelWindowMotif::DoSetSizeHints( int minW, int minH,
333 int maxW, int maxH,
334 int incW, int incH )
66f8b9ac 335{
024f89f9 336 wxTopLevelWindowBase::DoSetSizeHints( minW, minH, maxW, maxH, incW, incH );
66f8b9ac
MB
337
338 int count = 0;
339 Arg args[6];
340
341 if( minW > -1 ) { XtSetArg( args[count], XmNminWidth, minW ); ++count; }
342 if( minH > -1 ) { XtSetArg( args[count], XmNminHeight, minH ); ++count; }
343 if( maxW > -1 ) { XtSetArg( args[count], XmNmaxWidth, maxW ); ++count; }
344 if( maxH > -1 ) { XtSetArg( args[count], XmNmaxHeight, maxH ); ++count; }
345 if( incW > -1 ) { XtSetArg( args[count], XmNwidthInc, incW ); ++count; }
346 if( incH > -1 ) { XtSetArg( args[count], XmNheightInc, incH ); ++count; }
347
f58585c0 348 XtSetValues( (Widget)GetShellWidget(), args, count );
66f8b9ac
MB
349}
350
f7f78039
MB
351bool wxTopLevelWindowMotif::SetShape( const wxRegion& region )
352{
353 return wxDoSetShape( (Display*)GetXDisplay(),
354 XtWindow( (Widget)GetShellWidget() ),
355 region );
356}
357
0de6dfa7
MB
358// ---------------------------------------------------------------------------
359// Callback definition
360// ---------------------------------------------------------------------------
361
362// Handle a close event from the window manager
363static void wxCloseTLWCallback( Widget WXUNUSED(widget), XtPointer client_data,
364 XmAnyCallbackStruct *WXUNUSED(cbs) )
365{
366 wxTopLevelWindowMotif* tlw = (wxTopLevelWindowMotif*)client_data;
367 wxCloseEvent closeEvent( wxEVT_CLOSE_WINDOW, tlw->GetId() );
368 closeEvent.SetEventObject( tlw );
369
370 // May delete the dialog (with delayed deletion)
937013e0 371 tlw->HandleWindowEvent(closeEvent);
0de6dfa7
MB
372}
373
374void wxTLWEventHandler( Widget wid,
375 XtPointer WXUNUSED(client_data),
376 XEvent* event,
377 Boolean* continueToDispatch)
378{
379 wxTopLevelWindowMotif* tlw =
380 (wxTopLevelWindowMotif*)wxGetWindowFromTable( wid );
381
382 if( tlw )
383 {
384 wxMouseEvent wxevent( wxEVT_NULL );
385
386 if( wxTranslateMouseEvent( wxevent, tlw, wid, event ) )
387 {
388 wxevent.SetEventObject( tlw );
389 wxevent.SetId( tlw->GetId() );
937013e0 390 tlw->HandleWindowEvent( wxevent );
0de6dfa7
MB
391 }
392 else
393 {
394 // An attempt to implement OnCharHook by calling OnCharHook first;
96be256b 395 // if this returns true, set continueToDispatch to False
0de6dfa7
MB
396 // (don't continue processing).
397 // Otherwise set it to True and call OnChar.
398 wxKeyEvent keyEvent( wxEVT_CHAR );
399 if( wxTranslateKeyEvent( keyEvent, tlw, wid, event ))
400 {
401 keyEvent.SetEventObject( tlw );
402 keyEvent.SetId( tlw->GetId() );
403 keyEvent.SetEventType( wxEVT_CHAR_HOOK );
937013e0 404 if( tlw->HandleWindowEvent( keyEvent ) )
0de6dfa7
MB
405 {
406 *continueToDispatch = False;
407 return;
408 }
409 else
410 {
411 // For simplicity, OnKeyDown is the same as OnChar
412 // TODO: filter modifier key presses from OnChar
413 keyEvent.SetEventType( wxEVT_KEY_DOWN );
414
415 // Only process OnChar if OnKeyDown didn't swallow it
937013e0 416 if( !tlw->HandleWindowEvent( keyEvent ) )
0de6dfa7
MB
417 {
418 keyEvent.SetEventType( wxEVT_CHAR );
937013e0 419 tlw->HandleWindowEvent( keyEvent );
0de6dfa7
MB
420 }
421 }
422 }
423 }
424 }
425
426 *continueToDispatch = True;
427}