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