1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        src/motif/dialog.cpp
3 // Purpose:     wxDialog class
4 // Author:      Julian Smart
5 // Modified by:
6 // Created:     17/09/98
7 // Copyright:   (c) Julian Smart
8 // Licence:     wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
10 
11 // For compilers that support precompilation, includes "wx.h".
12 #include "wx/wxprec.h"
13 
14 #include "wx/dialog.h"
15 
16 #ifndef WX_PRECOMP
17     #include "wx/app.h"
18     #include "wx/utils.h"
19     #include "wx/settings.h"
20 #endif
21 
22 #include "wx/evtloop.h"
23 #include "wx/modalhook.h"
24 
25 #ifdef __VMS__
26 #pragma message disable nosimpint
27 #endif
28 #include <Xm/Xm.h>
29 
30 #include <X11/Shell.h>
31 #if XmVersion >= 1002
32 #include <Xm/XmAll.h>
33 #endif
34 #include <Xm/MwmUtil.h>
35 #include <Xm/Label.h>
36 #include <Xm/BulletinB.h>
37 #include <Xm/Frame.h>
38 #include <Xm/Text.h>
39 #include <Xm/DialogS.h>
40 #include <Xm/FileSB.h>
41 #include <Xm/RowColumn.h>
42 #include <Xm/LabelG.h>
43 #include <Xm/AtomMgr.h>
44 #if   XmVersion > 1000
45 #include <Xm/Protocols.h>
46 #endif
47 #ifdef __VMS__
48 #pragma message enable nosimpint
49 #endif
50 
51 #include "wx/motif/private.h"
52 
53 // A stack of modal_showing flags, since we can't rely
54 // on accessing wxDialog::m_modalShowing within
55 // wxDialog::Show in case a callback has deleted the wxDialog.
56 // static wxList wxModalShowingStack;
57 
58 // Lists to keep track of windows, so we can disable/enable them
59 // for modal dialogs
60 wxList wxModalDialogs;
61 extern wxList wxModelessWindows;  // Frames and modeless dialogs
62 
63 #define wxUSE_INVISIBLE_RESIZE 1
64 
wxDialog()65 wxDialog::wxDialog()
66 {
67     m_modalShowing = false;
68     m_eventLoop = NULL;
69 }
70 
Create(wxWindow * parent,wxWindowID id,const wxString & title,const wxPoint & pos,const wxSize & size,long style,const wxString & name)71 bool wxDialog::Create(wxWindow *parent, wxWindowID id,
72                       const wxString& title,
73                       const wxPoint& pos,
74                       const wxSize& size,
75                       long style,
76                       const wxString& name)
77 {
78     SetExtraStyle(GetExtraStyle() | wxTOPLEVEL_EX_DIALOG);
79 
80     if( !wxTopLevelWindow::Create( parent, id, title, pos, size, style,
81                                    name ) )
82         return false;
83 
84     m_modalShowing = false;
85     m_eventLoop = NULL;
86 
87     Widget dialogShell = (Widget) m_mainWidget;
88 
89     SetTitle( title );
90 
91     // Can't remember what this was about... but I think it's necessary.
92 #if wxUSE_INVISIBLE_RESIZE
93     if (pos.x > -1)
94         XtVaSetValues(dialogShell, XmNx, pos.x,
95         NULL);
96     if (pos.y > -1)
97         XtVaSetValues(dialogShell, XmNy, pos.y,
98         NULL);
99 
100     if (size.x > -1)
101         XtVaSetValues(dialogShell, XmNwidth, size.x, NULL);
102     if (size.y > -1)
103         XtVaSetValues(dialogShell, XmNheight, size.y, NULL);
104 #endif
105 
106     // Positioning of the dialog doesn't work properly unless the dialog
107     // is managed, so we manage without mapping to the screen.
108     // To show, we map the shell (actually it's parent).
109 #if !wxUSE_INVISIBLE_RESIZE
110     Widget shell = XtParent(dialogShell) ;
111     XtVaSetValues(shell, XmNmappedWhenManaged, False, NULL);
112 #endif
113 
114 #if !wxUSE_INVISIBLE_RESIZE
115     XtManageChild(dialogShell);
116     SetSize(pos.x, pos.y, size.x, size.y);
117 #endif
118 
119     XtAddEventHandler(dialogShell,ExposureMask,False,
120         wxUniversalRepaintProc, (XtPointer) this);
121 
122     PostCreation();
123 
124     return true;
125 }
126 
XmDoCreateTLW(wxWindow * parent,wxWindowID WXUNUSED (id),const wxString & WXUNUSED (title),const wxPoint & WXUNUSED (pos),const wxSize & WXUNUSED (size),long WXUNUSED (style),const wxString & name)127 bool wxDialog::XmDoCreateTLW(wxWindow* parent,
128                              wxWindowID WXUNUSED(id),
129                              const wxString& WXUNUSED(title),
130                              const wxPoint& WXUNUSED(pos),
131                              const wxSize& WXUNUSED(size),
132                              long WXUNUSED(style),
133                              const wxString& name)
134 {
135     Widget parentWidget = (Widget) 0;
136     if( parent )
137         parentWidget = (Widget) parent->GetTopWidget();
138     if( !parent )
139         parentWidget = (Widget) wxTheApp->GetTopLevelWidget();
140 
141     wxASSERT_MSG( (parentWidget != (Widget) 0),
142                   "Could not find a suitable parent shell for dialog." );
143 
144     Arg args[2];
145     XtSetArg (args[0], XmNdefaultPosition, False);
146     XtSetArg (args[1], XmNautoUnmanage, False);
147     Widget dialogShell =
148         XmCreateBulletinBoardDialog( parentWidget,
149                                      name.char_str(),
150                                      args, 2);
151     m_mainWidget = (WXWidget) dialogShell;
152 
153     // We don't want margins, since there is enough elsewhere.
154     XtVaSetValues( dialogShell,
155                    XmNmarginHeight,   0,
156                    XmNmarginWidth,    0,
157                    XmNresizePolicy, XmRESIZE_NONE,
158                    NULL ) ;
159 
160     XtTranslations ptr ;
161     XtOverrideTranslations(dialogShell,
162         ptr = XtParseTranslationTable("<Configure>: resize()"));
163     XtFree((char *)ptr);
164 
165     XtRealizeWidget(dialogShell);
166 
167     wxAddWindowToTable( (Widget)m_mainWidget, this );
168 
169     return true;
170 }
171 
SetModal(bool flag)172 void wxDialog::SetModal(bool flag)
173 {
174    if ( flag )
175        wxModelessWindows.DeleteObject(this);
176    else
177        wxModelessWindows.Append(this);
178 }
179 
~wxDialog()180 wxDialog::~wxDialog()
181 {
182     SendDestroyEvent();
183 
184     // if the dialog is modal, this will end its event loop
185     Show(false);
186 
187     delete m_eventLoop;
188 
189     if (m_mainWidget)
190     {
191         XtRemoveEventHandler((Widget) m_mainWidget, ExposureMask, False,
192                              wxUniversalRepaintProc, (XtPointer) this);
193     }
194 
195     m_modalShowing = false;
196 
197 #if !wxUSE_INVISIBLE_RESIZE
198     if (m_mainWidget)
199     {
200         XtUnmapWidget((Widget) m_mainWidget);
201     }
202 #endif
203 
204     PreDestroy();
205 
206     if ( m_mainWidget )
207     {
208         wxDeleteWindowFromTable( (Widget)m_mainWidget );
209         XtDestroyWidget( (Widget)m_mainWidget );
210     }
211 }
212 
DoSetSize(int x,int y,int width,int height,int sizeFlags)213 void wxDialog::DoSetSize(int x, int y, int width, int height, int sizeFlags)
214 {
215     XtVaSetValues((Widget) m_mainWidget, XmNresizePolicy, XmRESIZE_ANY, NULL);
216     wxWindow::DoSetSize(x, y, width, height, sizeFlags);
217     XtVaSetValues((Widget) m_mainWidget, XmNresizePolicy, XmRESIZE_NONE, NULL);
218 }
219 
DoSetClientSize(int width,int height)220 void wxDialog::DoSetClientSize(int width, int height)
221 {
222     wxWindow::SetSize(-1, -1, width, height);
223 }
224 
SetTitle(const wxString & title)225 void wxDialog::SetTitle(const wxString& title)
226 {
227     wxTopLevelWindow::SetTitle( title );
228 
229     if( !title.empty() )
230     {
231         wxXmString str( title );
232         XtVaSetValues( (Widget)m_mainWidget,
233                        XmNtitle, (const char*)title.mb_str(),
234                        XmNdialogTitle, str(),
235                        XmNiconName, (const char*)title.mb_str(),
236                        NULL );
237     }
238 }
239 
Show(bool show)240 bool wxDialog::Show( bool show )
241 {
242     if( !wxWindowBase::Show( show ) )
243         return false;
244 
245     if ( !show && IsModal() )
246         EndModal(wxID_CANCEL);
247 
248     m_isShown = show;
249 
250     if (show)
251     {
252         if (CanDoLayoutAdaptation())
253             DoLayoutAdaptation();
254 
255         // this usually will result in TransferDataToWindow() being called
256         // which will change the controls values so do it before showing as
257         // otherwise we could have some flicker
258         InitDialog();
259     }
260 
261     if (show)
262     {
263 #if !wxUSE_INVISIBLE_RESIZE
264         XtMapWidget(XtParent((Widget) m_mainWidget));
265 #else
266         XtManageChild((Widget)m_mainWidget) ;
267 #endif
268 
269         XRaiseWindow( XtDisplay( (Widget)m_mainWidget ),
270                       XtWindow( (Widget)m_mainWidget) );
271 
272     }
273     else
274     {
275 #if !wxUSE_INVISIBLE_RESIZE
276         XtUnmapWidget(XtParent((Widget) m_mainWidget));
277 #else
278         XtUnmanageChild((Widget)m_mainWidget) ;
279 #endif
280 
281         XFlush(XtDisplay((Widget)m_mainWidget));
282         XSync(XtDisplay((Widget)m_mainWidget), False);
283     }
284 
285     return true;
286 }
287 
288 // Shows a dialog modally, returning a return code
ShowModal()289 int wxDialog::ShowModal()
290 {
291     WX_HOOK_MODAL_DIALOG();
292 
293     Show(true);
294 
295     // after the event loop ran, the widget might already have been destroyed
296     WXDisplay* display = (WXDisplay*)XtDisplay( (Widget)m_mainWidget );
297 
298     if (m_modalShowing)
299         return 0;
300     m_eventLoop = new wxEventLoop;
301 
302     m_modalShowing = true;
303     XtAddGrab((Widget) m_mainWidget, True, False);
304 
305     m_eventLoop->Run();
306 
307     // Now process all events in case they get sent to a destroyed dialog
308     wxFlushEvents( display );
309 
310     wxDELETE(m_eventLoop);
311 
312     // TODO: is it safe to call this, if the dialog may have been deleted
313     // by now? Probably only if we're using delayed deletion of dialogs.
314     return GetReturnCode();
315 }
316 
EndModal(int retCode)317 void wxDialog::EndModal(int retCode)
318 {
319     if (!m_modalShowing)
320         return;
321 
322     SetReturnCode(retCode);
323 
324     // Strangely, we don't seem to need this now.
325     //    XtRemoveGrab((Widget) m_mainWidget);
326 
327     Show(false);
328 
329     m_modalShowing = false;
330     m_eventLoop->Exit();
331 
332     SetModal(false);
333 }
334 
335 // Destroy the window (delayed, if a managed window)
Destroy()336 bool wxDialog::Destroy()
337 {
338     if (!wxPendingDelete.Member(this))
339         wxPendingDelete.Append(this);
340     return true;
341 }
342 
ChangeFont(bool keepOriginalSize)343 void wxDialog::ChangeFont(bool keepOriginalSize)
344 {
345     wxWindow::ChangeFont(keepOriginalSize);
346 }
347 
ChangeBackgroundColour()348 void wxDialog::ChangeBackgroundColour()
349 {
350     if (GetMainWidget())
351         wxDoChangeBackgroundColour(GetMainWidget(), m_backgroundColour);
352 }
353 
ChangeForegroundColour()354 void wxDialog::ChangeForegroundColour()
355 {
356     if (GetMainWidget())
357         wxDoChangeForegroundColour(GetMainWidget(), m_foregroundColour);
358 }
359