]> git.saurik.com Git - wxWidgets.git/blame - src/motif/dialog.cpp
Clean-up, speed-up and bug-fix for wxListCtrl drawing,
[wxWidgets.git] / src / motif / dialog.cpp
CommitLineData
4bb6408c
JS
1/////////////////////////////////////////////////////////////////////////////
2// Name: dialog.cpp
3// Purpose: wxDialog class
4// Author: Julian Smart
5// Modified by:
6// Created: 17/09/98
7// RCS-ID: $Id$
8// Copyright: (c) Julian Smart
dfe1eee3 9// Licence: wxWindows licence
4bb6408c
JS
10/////////////////////////////////////////////////////////////////////////////
11
12#ifdef __GNUG__
13#pragma implementation "dialog.h"
14#endif
15
16#include "wx/dialog.h"
17#include "wx/utils.h"
18#include "wx/frame.h"
19#include "wx/app.h"
20#include "wx/settings.h"
21
338dd992
JJ
22#ifdef __VMS__
23#pragma message disable nosimpint
24#endif
dfc54541
JS
25#include <Xm/Xm.h>
26
27#include <X11/Shell.h>
28#if XmVersion >= 1002
29#include <Xm/XmAll.h>
30#endif
31#include <Xm/MwmUtil.h>
32#include <Xm/Label.h>
33#include <Xm/BulletinB.h>
34#include <Xm/Frame.h>
35#include <Xm/Text.h>
36#include <Xm/DialogS.h>
37#include <Xm/FileSB.h>
38#include <Xm/RowColumn.h>
39#include <Xm/LabelG.h>
40#include <Xm/AtomMgr.h>
41#if XmVersion > 1000
42#include <Xm/Protocols.h>
43#endif
338dd992
JJ
44#ifdef __VMS__
45#pragma message enable nosimpint
46#endif
dfc54541
JS
47
48#include "wx/motif/private.h"
49
50static void wxCloseDialogCallback(Widget widget, XtPointer client_data, XmAnyCallbackStruct *cbs);
dfc54541 51static void wxDialogBoxEventHandler (Widget wid,
2d120f83
JS
52 XtPointer client_data,
53 XEvent* event,
54 Boolean *continueToDispatch);
dfc54541
JS
55
56static void wxUnmapBulletinBoard(Widget dialog, wxDialog *client,XtPointer call);
57
58// A stack of modal_showing flags, since we can't rely
59// on accessing wxDialog::m_modalShowing within
60// wxDialog::Show in case a callback has deleted the wxDialog.
61static wxList wxModalShowingStack;
62
4bb6408c
JS
63// Lists to keep track of windows, so we can disable/enable them
64// for modal dialogs
65wxList wxModalDialogs;
66wxList wxModelessWindows; // Frames and modeless dialogs
67extern wxList wxPendingDelete;
68
47d67540 69#define wxUSE_INVISIBLE_RESIZE 1
dfc54541 70
4bb6408c
JS
71IMPLEMENT_DYNAMIC_CLASS(wxDialog, wxPanel)
72
73BEGIN_EVENT_TABLE(wxDialog, wxPanel)
8e877c19
RR
74 EVT_SIZE(wxDialog::OnSize)
75 EVT_BUTTON(wxID_OK, wxDialog::OnOK)
76 EVT_BUTTON(wxID_APPLY, wxDialog::OnApply)
77 EVT_BUTTON(wxID_CANCEL, wxDialog::OnCancel)
78 EVT_CHAR_HOOK(wxDialog::OnCharHook)
79 EVT_SYS_COLOUR_CHANGED(wxDialog::OnSysColourChanged)
80 EVT_CLOSE(wxDialog::OnCloseWindow)
4bb6408c
JS
81END_EVENT_TABLE()
82
4bb6408c
JS
83
84wxDialog::wxDialog()
85{
dfc54541 86 m_modalShowing = FALSE;
0d57be45 87 m_backgroundColour = wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DFACE);
4bb6408c
JS
88}
89
90bool wxDialog::Create(wxWindow *parent, wxWindowID id,
2d120f83
JS
91 const wxString& title,
92 const wxPoint& pos,
93 const wxSize& size,
94 long style,
95 const wxString& name)
4bb6408c 96{
dfc54541
JS
97 m_windowStyle = style;
98 m_modalShowing = FALSE;
99 m_dialogTitle = title;
dfe1eee3 100
0d57be45
JS
101 m_backgroundColour = wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DFACE);
102 m_foregroundColour = *wxBLACK;
dfe1eee3 103
dfc54541 104 SetName(name);
dfe1eee3 105
dfc54541
JS
106 if (!parent)
107 wxTopLevelWindows.Append(this);
dfe1eee3 108
dfc54541 109 if (parent) parent->AddChild(this);
dfe1eee3 110
dfc54541
JS
111 if ( id == -1 )
112 m_windowId = (int)NewControlId();
113 else
114 m_windowId = id;
dfe1eee3 115
dfc54541
JS
116 Widget parentWidget = (Widget) 0;
117 if (parent)
118 parentWidget = (Widget) parent->GetTopWidget();
119 if (!parent)
120 parentWidget = (Widget) wxTheApp->GetTopLevelWidget();
dfe1eee3 121
dfc54541 122 wxASSERT_MSG( (parentWidget != (Widget) 0), "Could not find a suitable parent shell for dialog." );
dfe1eee3 123
94b49b93 124 Arg args[2];
dfc54541 125 XtSetArg (args[0], XmNdefaultPosition, False);
94b49b93
JS
126 XtSetArg (args[1], XmNautoUnmanage, False);
127 Widget dialogShell = XmCreateBulletinBoardDialog(parentWidget, (char*) (const char*) name, args, 2);
dfc54541 128 m_mainWidget = (WXWidget) dialogShell;
dfe1eee3 129
dfc54541
JS
130 // We don't want margins, since there is enough elsewhere.
131 XtVaSetValues(dialogShell,
2d120f83
JS
132 XmNmarginHeight, 0,
133 XmNmarginWidth, 0,
134 XmNresizePolicy, XmRESIZE_NONE,
135 NULL) ;
dfe1eee3 136
dfc54541
JS
137 Widget shell = XtParent(dialogShell) ;
138 if (!title.IsNull())
139 {
140 XmString str = XmStringCreateSimple((char*) (const char*)title);
141 XtVaSetValues(dialogShell,
2d120f83
JS
142 XmNdialogTitle, str,
143 NULL);
dfc54541
JS
144 XmStringFree(str);
145 }
dfe1eee3 146
da175b2c 147 m_font = wxSystemSettings::GetSystemFont(wxSYS_DEFAULT_GUI_FONT);
4b5f3fe6 148 ChangeFont(FALSE);
dfe1eee3 149
dfc54541 150 wxAddWindowToTable(dialogShell, this);
dfe1eee3 151
dfc54541
JS
152 // Intercept CLOSE messages from the window manager
153 Atom WM_DELETE_WINDOW = XmInternAtom(XtDisplay(shell), "WM_DELETE_WINDOW", False);
dfe1eee3 154
4b5f3fe6 155 /* Remove and add WM_DELETE_WINDOW so ours is only handler */
dfc54541
JS
156 /* Why do we have to do this for wxDialog, but not wxFrame? */
157 XmRemoveWMProtocols(shell, &WM_DELETE_WINDOW, 1);
158 XmAddWMProtocols(shell, &WM_DELETE_WINDOW, 1);
159 XmActivateWMProtocol(shell, WM_DELETE_WINDOW);
dfe1eee3 160
dfc54541
JS
161 // Modified Steve Hammes for Motif 2.0
162#if (XmREVISION > 1 || XmVERSION > 1)
163 XmAddWMProtocolCallback(shell, WM_DELETE_WINDOW, (XtCallbackProc) wxCloseDialogCallback, (XtPointer)this);
164#elif XmREVISION == 1
165 XmAddWMProtocolCallback(shell, WM_DELETE_WINDOW, (XtCallbackProc) wxCloseDialogCallback, (caddr_t)this);
166#else
167 XmAddWMProtocolCallback(shell, WM_DELETE_WINDOW, (void (*)())wxCloseDialogCallback, (caddr_t)this);
168#endif
dfe1eee3 169
dfc54541
JS
170 XtTranslations ptr ;
171 XtOverrideTranslations(dialogShell,
2d120f83 172 ptr = XtParseTranslationTable("<Configure>: resize()"));
dfc54541 173 XtFree((char *)ptr);
dfe1eee3 174
dfc54541 175 // Can't remember what this was about... but I think it's necessary.
dfe1eee3 176
dfad0599 177 if (wxUSE_INVISIBLE_RESIZE)
dfc54541 178 {
2d120f83
JS
179 if (pos.x > -1)
180 XtVaSetValues(dialogShell, XmNx, pos.x,
181 NULL);
182 if (pos.y > -1)
183 XtVaSetValues(dialogShell, XmNy, pos.y,
184 NULL);
dfe1eee3 185
2d120f83
JS
186 if (size.x > -1)
187 XtVaSetValues(dialogShell, XmNwidth, size.x, NULL);
188 if (size.y > -1)
189 XtVaSetValues(dialogShell, XmNheight, size.y, NULL);
dfc54541 190 }
dfe1eee3 191
dfc54541
JS
192 // This patch come from Torsten Liermann lier@lier1.muc.de
193 if (XmIsMotifWMRunning(shell))
194 {
195 int decor = 0 ;
196 if (m_windowStyle & wxRESIZE_BORDER)
2d120f83 197 decor |= MWM_DECOR_RESIZEH ;
dfc54541 198 if (m_windowStyle & wxSYSTEM_MENU)
2d120f83 199 decor |= MWM_DECOR_MENU;
dfc54541
JS
200 if ((m_windowStyle & wxCAPTION) ||
201 (m_windowStyle & wxTINY_CAPTION_HORIZ) ||
202 (m_windowStyle & wxTINY_CAPTION_VERT))
2d120f83 203 decor |= MWM_DECOR_TITLE;
dfc54541 204 if (m_windowStyle & wxTHICK_FRAME)
2d120f83 205 decor |= MWM_DECOR_BORDER;
dfc54541 206 if (m_windowStyle & wxMINIMIZE_BOX)
2d120f83 207 decor |= MWM_DECOR_MINIMIZE;
dfc54541 208 if (m_windowStyle & wxMAXIMIZE_BOX)
2d120f83 209 decor |= MWM_DECOR_MAXIMIZE;
dfe1eee3 210
dfc54541
JS
211 XtVaSetValues(shell,XmNmwmDecorations,decor,NULL) ;
212 }
213 // This allows non-Motif window managers to support at least the
214 // no-decorations case.
215 else
216 {
2d120f83
JS
217 if ((m_windowStyle & wxCAPTION) != wxCAPTION)
218 XtVaSetValues((Widget) shell,XmNoverrideRedirect,TRUE,NULL);
dfc54541 219 }
dfe1eee3 220
dfc54541 221 XtRealizeWidget(dialogShell);
dfe1eee3 222
dfc54541 223 XtAddCallback(dialogShell,XmNunmapCallback,
2d120f83 224 (XtCallbackProc)wxUnmapBulletinBoard,this) ;
dfe1eee3 225
dfc54541
JS
226 // Positioning of the dialog doesn't work properly unless the dialog
227 // is managed, so we manage without mapping to the screen.
228 // To show, we map the shell (actually it's parent).
dfad0599 229 if (!wxUSE_INVISIBLE_RESIZE)
dfc54541 230 XtVaSetValues(shell, XmNmappedWhenManaged, FALSE, NULL);
dfe1eee3 231
dfad0599 232 if (!wxUSE_INVISIBLE_RESIZE)
dfc54541
JS
233 {
234 XtManageChild(dialogShell);
235 SetSize(pos.x, pos.y, size.x, size.y);
236 }
237 XtAddEventHandler(dialogShell,ExposureMask,FALSE,
2e35f56f 238 wxUniversalRepaintProc, (XtPointer) this);
dfe1eee3 239
dfc54541 240 XtAddEventHandler(dialogShell,
2d120f83
JS
241 ButtonPressMask | ButtonReleaseMask | PointerMotionMask | KeyPressMask,
242 FALSE,
243 wxDialogBoxEventHandler,
244 (XtPointer)this);
dfe1eee3 245
0d57be45 246 ChangeBackgroundColour();
dfe1eee3 247
dfc54541 248 return TRUE;
4bb6408c
JS
249}
250
251void wxDialog::SetModal(bool flag)
252{
dfc54541
JS
253 if ( flag )
254 m_windowStyle |= wxDIALOG_MODAL ;
255 else
256 if ( m_windowStyle & wxDIALOG_MODAL )
2d120f83 257 m_windowStyle -= wxDIALOG_MODAL ;
dfe1eee3 258
2d120f83
JS
259 wxModelessWindows.DeleteObject(this);
260 if (!flag)
261 wxModelessWindows.Append(this);
4bb6408c
JS
262}
263
264wxDialog::~wxDialog()
265{
3ab377bd
MB
266 m_isBeingDeleted = TRUE;
267
2e35f56f
JS
268 if (m_mainWidget)
269 XtRemoveEventHandler((Widget) m_mainWidget, ExposureMask, FALSE,
270 wxUniversalRepaintProc, (XtPointer) this);
dfe1eee3 271
dfc54541 272 m_modalShowing = FALSE;
dfad0599 273 if (!wxUSE_INVISIBLE_RESIZE && m_mainWidget)
dfc54541 274 {
2d120f83 275 XtUnmapWidget((Widget) m_mainWidget);
dfc54541 276 }
dfe1eee3 277
4bb6408c 278 wxTopLevelWindows.DeleteObject(this);
dfe1eee3 279
4bb6408c 280 if ( (GetWindowStyleFlag() & wxDIALOG_MODAL) != wxDIALOG_MODAL )
2d120f83 281 wxModelessWindows.DeleteObject(this);
dfe1eee3 282
4bb6408c
JS
283 // If this is the last top-level window, exit.
284 if (wxTheApp && (wxTopLevelWindows.Number() == 0))
285 {
2d120f83 286 wxTheApp->SetTopWindow(NULL);
dfe1eee3 287
2d120f83
JS
288 if (wxTheApp->GetExitOnFrameDelete())
289 {
290 wxTheApp->ExitMainLoop();
291 }
4bb6408c 292 }
dfe1eee3 293
dfc54541
JS
294 // This event-flushing code used to be in wxWindow::PostDestroyChildren (wx_dialog.cpp)
295 // but I think this should work, if we destroy the children first.
296 // Note that this might need to be done for wxFrame also.
297 DestroyChildren();
cba2db0c
JS
298
299 // The idea about doing it here is that if you have to remove the
300 // XtDestroyWidget from ~wxWindow, at least top-level windows
301 // will still be deleted (and destroy children implicitly).
302 if (GetMainWidget())
303 {
304 DetachWidget(GetMainWidget()); // Removes event handlers
305 XtDestroyWidget((Widget) GetMainWidget());
306 SetMainWidget((WXWidget) NULL);
dfc54541 307 }
4bb6408c
JS
308}
309
310// By default, pressing escape cancels the dialog
311void wxDialog::OnCharHook(wxKeyEvent& event)
312{
2d120f83
JS
313 if (event.m_keyCode == WXK_ESCAPE)
314 {
315 // Behaviour changed in 2.0: we'll send a Cancel message
316 // to the dialog instead of Close.
317 wxCommandEvent cancelEvent(wxEVT_COMMAND_BUTTON_CLICKED, wxID_CANCEL);
318 cancelEvent.SetEventObject( this );
319 GetEventHandler()->ProcessEvent(cancelEvent);
dfe1eee3 320
2d120f83
JS
321 return;
322 }
323 // We didn't process this event.
324 event.Skip();
4bb6408c
JS
325}
326
327void wxDialog::Iconize(bool WXUNUSED(iconize))
328{
2d120f83
JS
329 // Can't iconize a dialog in Motif, apparently
330 // TODO: try using the parent of m_mainShell.
331 // XtVaSetValues((Widget) m_mainWidget, XmNiconic, iconize, NULL);
4bb6408c
JS
332}
333
8e877c19
RR
334// Default resizing behaviour - if only ONE subwindow,
335// resize to client rectangle size
af111fc3 336void wxDialog::OnSize(wxSizeEvent& WXUNUSED(event))
8e877c19
RR
337{
338 // if we're using constraints - do use them
339#if wxUSE_CONSTRAINTS
340 if ( GetAutoLayout() ) {
341 Layout();
342 return;
343 }
344#endif
345
346 // do we have _exactly_ one child?
347 wxWindow *child = NULL;
348 for ( wxNode *node = GetChildren().First(); node; node = node->Next() )
349 {
350 wxWindow *win = (wxWindow *)node->Data();
351 if ( !win->IsKindOf(CLASSINFO(wxFrame)) &&
352 !win->IsKindOf(CLASSINFO(wxDialog)) )
353 {
354 if ( child )
355 return; // it's our second subwindow - nothing to do
356 child = win;
357 }
358 }
359
360 if ( child ) {
361 // we have exactly one child - set it's size to fill the whole frame
362 int clientW, clientH;
363 GetClientSize(&clientW, &clientH);
364
365 int x = 0;
366 int y = 0;
367
368 child->SetSize(x, y, clientW, clientH);
369 }
370}
371
372
4bb6408c
JS
373bool wxDialog::IsIconized() const
374{
2d120f83
JS
375/*
376Boolean iconic;
377XtVaGetValues((Widget) m_mainWidget, XmNiconic, &iconic, NULL);
dfc54541 378
2d120f83
JS
379 return iconic;
380 */
4bb6408c
JS
381 return FALSE;
382}
383
bfc6fde4 384void wxDialog::DoSetSize(int x, int y, int width, int height, int sizeFlags)
4bb6408c 385{
dfc54541 386 XtVaSetValues((Widget) m_mainWidget, XmNresizePolicy, XmRESIZE_ANY, NULL);
bfc6fde4 387 wxWindow::DoSetSize(x, y, width, height, sizeFlags);
dfc54541 388 XtVaSetValues((Widget) m_mainWidget, XmNresizePolicy, XmRESIZE_NONE, NULL);
4bb6408c
JS
389}
390
ad813b00
JS
391void wxDialog::DoSetClientSize(int width, int height)
392{
393 wxWindow::SetSize(-1, -1, width, height);
394}
395
4bb6408c
JS
396void wxDialog::SetTitle(const wxString& title)
397{
dfc54541
JS
398 m_dialogTitle = title;
399 if (!title.IsNull())
400 {
401 XmString str = XmStringCreateSimple((char*) (const char*) title);
dfe1eee3 402 XtVaSetValues((Widget) m_mainWidget,
2d120f83
JS
403 XmNtitle, (char*) (const char*) title,
404 XmNdialogTitle, str, // Roberto Cocchi
405 XmNiconName, (char*) (const char*) title,
406 NULL);
dfc54541
JS
407 XmStringFree(str);
408 }
4bb6408c
JS
409}
410
411wxString wxDialog::GetTitle() const
412{
2d120f83 413 return m_dialogTitle;
4bb6408c
JS
414}
415
dfc54541
JS
416void wxDialog::Raise()
417{
418 Window parent_window = XtWindow((Widget) m_mainWidget),
2d120f83
JS
419 next_parent = XtWindow((Widget) m_mainWidget),
420 root = RootWindowOfScreen(XtScreen((Widget) m_mainWidget));
dfc54541
JS
421 // search for the parent that is child of ROOT, because the WM may
422 // reparent twice and notify only the next parent (like FVWM)
423 while (next_parent != root) {
2d120f83
JS
424 Window *theChildren; unsigned int n;
425 parent_window = next_parent;
426 XQueryTree(XtDisplay((Widget) m_mainWidget), parent_window, &root,
427 &next_parent, &theChildren, &n);
428 XFree(theChildren); // not needed
dfc54541
JS
429 }
430 XRaiseWindow(XtDisplay((Widget) m_mainWidget), parent_window);
431}
432
433void wxDialog::Lower()
434{
435 Window parent_window = XtWindow((Widget) m_mainWidget),
2d120f83
JS
436 next_parent = XtWindow((Widget) m_mainWidget),
437 root = RootWindowOfScreen(XtScreen((Widget) m_mainWidget));
dfc54541
JS
438 // search for the parent that is child of ROOT, because the WM may
439 // reparent twice and notify only the next parent (like FVWM)
440 while (next_parent != root) {
2d120f83
JS
441 Window *theChildren; unsigned int n;
442 parent_window = next_parent;
443 XQueryTree(XtDisplay((Widget) m_mainWidget), parent_window, &root,
444 &next_parent, &theChildren, &n);
445 XFree(theChildren); // not needed
dfc54541
JS
446 }
447 XLowerWindow(XtDisplay((Widget) m_mainWidget), parent_window);
448}
449
450bool wxDialog::Show(bool show)
451{
452 m_isShown = show;
dfe1eee3 453
dfc54541
JS
454 if (show)
455 {
dfad0599 456 if (!wxUSE_INVISIBLE_RESIZE)
2d120f83 457 XtMapWidget(XtParent((Widget) m_mainWidget));
dfc54541 458 else
dfe1eee3
VZ
459 XtManageChild((Widget) m_mainWidget) ;
460
dfc54541 461 XRaiseWindow(XtDisplay((Widget) m_mainWidget), XtWindow((Widget) m_mainWidget));
dfe1eee3 462
dfc54541
JS
463 }
464 else
465 {
dfad0599 466 if (!wxUSE_INVISIBLE_RESIZE)
dfc54541
JS
467 XtUnmapWidget(XtParent((Widget) m_mainWidget));
468 else
469 XtUnmanageChild((Widget) m_mainWidget) ;
dfe1eee3 470
2d120f83
JS
471 XFlush(XtDisplay((Widget) wxTheApp->GetTopLevelWidget()));
472 XSync(XtDisplay((Widget) wxTheApp->GetTopLevelWidget()), FALSE);
dfc54541 473 }
dfe1eee3 474
dfc54541
JS
475 return TRUE;
476}
477
478// Shows a dialog modally, returning a return code
4bb6408c
JS
479int wxDialog::ShowModal()
480{
481 m_windowStyle |= wxDIALOG_MODAL;
dfe1eee3 482
dfc54541 483 Show(TRUE);
dfe1eee3 484
dfc54541
JS
485 if (m_modalShowing)
486 return 0;
dfe1eee3 487
dfc54541 488 wxModalShowingStack.Insert((wxObject *)TRUE);
dfe1eee3 489
dfc54541 490 m_modalShowing = TRUE;
793f619f 491 XtAddGrab((Widget) m_mainWidget, TRUE, FALSE);
dfe1eee3 492
dfc54541 493 XEvent event;
dfe1eee3 494
dfc54541 495 // Loop until we signal that the dialog should be closed
5dcf05ae 496 while ((wxModalShowingStack.Number() > 0) && ((int)(wxModalShowingStack.First()->Data()) != 0))
dfc54541 497 {
2d120f83 498 // XtAppProcessEvent((XtAppContext) wxTheApp->GetAppContext(), XtIMAll);
dfe1eee3 499
8aa04e8b
JS
500 XtAppNextEvent((XtAppContext) wxTheApp->GetAppContext(), &event);
501 wxTheApp->ProcessXEvent((WXEvent*) &event);
dfc54541 502 }
dfe1eee3 503
dfc54541
JS
504 // Remove modal dialog flag from stack
505 wxNode *node = wxModalShowingStack.First();
506 if (node)
2d120f83 507 delete node;
dfe1eee3 508
dfc54541
JS
509 // Now process all events in case they get sent to a destroyed dialog
510 XSync(XtDisplay((Widget) wxTheApp->GetTopLevelWidget()), FALSE);
511 while (XtAppPending((XtAppContext) wxTheApp->GetAppContext()))
512 {
513 XFlush(XtDisplay((Widget) wxTheApp->GetTopLevelWidget()));
514 XtAppNextEvent((XtAppContext) wxTheApp->GetAppContext(), &event);
dfe1eee3 515
8aa04e8b 516 wxTheApp->ProcessXEvent((WXEvent*) &event);
dfc54541 517 }
dfe1eee3 518
dfc54541
JS
519 // TODO: is it safe to call this, if the dialog may have been deleted
520 // by now? Probably only if we're using delayed deletion of dialogs.
521 return GetReturnCode();
4bb6408c
JS
522}
523
524void wxDialog::EndModal(int retCode)
525{
dfc54541
JS
526 if (!m_modalShowing)
527 return;
dfe1eee3 528
dfc54541 529 SetReturnCode(retCode);
dfe1eee3 530
88150e60
JS
531 // Strangely, we don't seem to need this now.
532 // XtRemoveGrab((Widget) m_mainWidget);
dfe1eee3 533
dfc54541 534 Show(FALSE);
dfe1eee3 535
dfc54541 536 m_modalShowing = FALSE;
dfe1eee3 537
dfc54541
JS
538 wxNode *node = wxModalShowingStack.First();
539 if (node)
2d120f83 540 node->SetData((wxObject *)FALSE);
4bb6408c
JS
541}
542
543// Standard buttons
f9e02ac7 544void wxDialog::OnOK(wxCommandEvent& WXUNUSED(event))
4bb6408c 545{
2d120f83
JS
546 if ( Validate() && TransferDataFromWindow() )
547 {
4bb6408c
JS
548 if ( IsModal() )
549 EndModal(wxID_OK);
550 else
551 {
2d120f83
JS
552 SetReturnCode(wxID_OK);
553 this->Show(FALSE);
4bb6408c 554 }
2d120f83 555 }
4bb6408c
JS
556}
557
f9e02ac7 558void wxDialog::OnApply(wxCommandEvent& WXUNUSED(event))
4bb6408c 559{
2d120f83
JS
560 if (Validate())
561 TransferDataFromWindow();
562 // TODO probably need to disable the Apply button until things change again
4bb6408c
JS
563}
564
f9e02ac7 565void wxDialog::OnCancel(wxCommandEvent& WXUNUSED(event))
4bb6408c
JS
566{
567 if ( IsModal() )
568 EndModal(wxID_CANCEL);
569 else
570 {
571 SetReturnCode(wxID_CANCEL);
2d120f83 572 this->Show(FALSE);
4bb6408c
JS
573 }
574}
575
af111fc3 576void wxDialog::OnCloseWindow(wxCloseEvent& WXUNUSED(event))
4bb6408c 577{
e3065973 578 // We'll send a Cancel message by default,
4bb6408c 579 // which may close the dialog.
e3065973
JS
580 // Check for looping if the Cancel event handler calls Close().
581
582 // Note that if a cancel button and handler aren't present in the dialog,
583 // nothing will happen when you close the dialog via the window manager, or
584 // via Close().
585 // We wouldn't want to destroy the dialog by default, since the dialog may have been
586 // created on the stack.
587 // However, this does mean that calling dialog->Close() won't delete the dialog
588 // unless the handler for wxID_CANCEL does so. So use Destroy() if you want to be
589 // sure to destroy the dialog.
590 // The default OnCancel (above) simply ends a modal dialog, and hides a modeless dialog.
591
4bb6408c 592 static wxList closing;
dfe1eee3 593
4bb6408c 594 if ( closing.Member(this) )
e3065973 595 return;
dfe1eee3 596
4bb6408c 597 closing.Append(this);
dfe1eee3 598
2d120f83
JS
599 wxCommandEvent cancelEvent(wxEVT_COMMAND_BUTTON_CLICKED, wxID_CANCEL);
600 cancelEvent.SetEventObject( this );
e3065973 601 GetEventHandler()->ProcessEvent(cancelEvent); // This may close the dialog
4bb6408c 602
e3065973 603 closing.DeleteObject(this);
4bb6408c
JS
604}
605
d75638f8
RR
606void wxDialog::OnPaint(wxPaintEvent &WXUNUSED(event))
607{
608 // added for compatiblity only
609}
610
4bb6408c
JS
611// Destroy the window (delayed, if a managed window)
612bool wxDialog::Destroy()
613{
2d120f83
JS
614 if (!wxPendingDelete.Member(this))
615 wxPendingDelete.Append(this);
616 return TRUE;
4bb6408c
JS
617}
618
f9e02ac7 619void wxDialog::OnSysColourChanged(wxSysColourChangedEvent& WXUNUSED(event))
4bb6408c 620{
2d120f83
JS
621 SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DFACE));
622 Refresh();
4bb6408c
JS
623}
624
dfc54541 625// Handle a close event from the window manager
dfe1eee3 626static void wxCloseDialogCallback( Widget WXUNUSED(widget), XtPointer client_data,
2d120f83 627 XmAnyCallbackStruct *WXUNUSED(cbs))
dfc54541 628{
2d120f83
JS
629 wxDialog *dialog = (wxDialog *)client_data;
630 wxCloseEvent closeEvent(wxEVT_CLOSE_WINDOW, dialog->GetId());
631 closeEvent.SetEventObject(dialog);
dfe1eee3 632
2d120f83
JS
633 // May delete the dialog (with delayed deletion)
634 dialog->GetEventHandler()->ProcessEvent(closeEvent);
dfc54541
JS
635}
636
dfe1eee3
VZ
637void wxDialogBoxEventHandler(Widget wid,
638 XtPointer WXUNUSED(client_data),
639 XEvent* event,
640 Boolean* continueToDispatch)
2d120f83 641{
dfe1eee3 642 wxDialog *dialog = (wxDialog *)wxGetWindowFromTable(wid);
2d120f83 643 if (dialog)
dfc54541 644 {
2d120f83
JS
645 wxMouseEvent wxevent(wxEVT_NULL);
646 if (wxTranslateMouseEvent(wxevent, dialog, wid, event))
dfc54541 647 {
2d120f83
JS
648 wxevent.SetEventObject(dialog);
649 wxevent.SetId(dialog->GetId());
650 dialog->GetEventHandler()->ProcessEvent(wxevent);
dfc54541
JS
651 }
652 else
653 {
2d120f83
JS
654 // An attempt to implement OnCharHook by calling OnCharHook first;
655 // if this returns TRUE, set continueToDispatch to False
656 // (don't continue processing).
657 // Otherwise set it to True and call OnChar.
c75e6695 658 wxKeyEvent keyEvent(wxEVT_CHAR);
2d120f83
JS
659 if (wxTranslateKeyEvent(keyEvent, dialog, wid, event))
660 {
661 keyEvent.SetEventObject(dialog);
662 keyEvent.SetId(dialog->GetId());
663 keyEvent.SetEventType(wxEVT_CHAR_HOOK);
664 if (dialog->GetEventHandler()->ProcessEvent(keyEvent))
665 {
666 *continueToDispatch = False;
667 return;
668 }
669 else
670 {
a91b47e8
JS
671 // For simplicity, OnKeyDown is the same as OnChar
672 // TODO: filter modifier key presses from OnChar
673 keyEvent.SetEventType(wxEVT_KEY_DOWN);
674
675 // Only process OnChar if OnKeyDown didn't swallow it
676 if (!dialog->GetEventHandler()->ProcessEvent (keyEvent))
677 {
678 keyEvent.SetEventType(wxEVT_CHAR);
679 dialog->GetEventHandler()->ProcessEvent(keyEvent);
dfe1eee3 680 }
2d120f83
JS
681 }
682 }
683 }
dfc54541 684 }
2d120f83 685 *continueToDispatch = True;
dfc54541
JS
686}
687
f9e02ac7 688static void wxUnmapBulletinBoard(Widget WXUNUSED(dialog), wxDialog *WXUNUSED(client), XtPointer WXUNUSED(call) )
dfc54541 689{
2d120f83
JS
690/* This gets called when the dialog is being shown, which
691* defeats modal showing.
692client->m_modalShowing = FALSE ;
693client->m_isShown = FALSE;
694 */
dfc54541 695}
0d57be45 696
94b49b93 697void wxDialog::ChangeFont(bool keepOriginalSize)
0d57be45 698{
94b49b93 699 wxWindow::ChangeFont(keepOriginalSize);
0d57be45
JS
700}
701
702void wxDialog::ChangeBackgroundColour()
703{
94b49b93
JS
704 if (GetMainWidget())
705 DoChangeBackgroundColour(GetMainWidget(), m_backgroundColour);
0d57be45
JS
706}
707
708void wxDialog::ChangeForegroundColour()
709{
94b49b93
JS
710 if (GetMainWidget())
711 DoChangeForegroundColour(GetMainWidget(), m_foregroundColour);
0d57be45
JS
712}
713