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