1 ///////////////////////////////////////////////////////////////////////////// 
   4 // Author:      Robert Roebling 
   6 // Copyright:   (c) 1998 Robert Roebling 
   7 // Licence:     wxWindows licence 
   8 ///////////////////////////////////////////////////////////////////////////// 
  11 #pragma implementation "dialog.h" 
  14 #include "wx/dialog.h" 
  20 #include "wx/gtk/win_gtk.h" 
  21 #include "wx/cursor.h" 
  24 #include "gdk/gdkprivate.h" 
  28 //----------------------------------------------------------------------------- 
  30 //----------------------------------------------------------------------------- 
  32 extern void wxapp_install_idle_handler(); 
  35 //----------------------------------------------------------------------------- 
  37 //----------------------------------------------------------------------------- 
  39 extern wxList wxPendingDelete
; 
  42 //----------------------------------------------------------------------------- 
  43 // instruct X to set the WM hint for positioning 
  44 //----------------------------------------------------------------------------- 
  48 static void gdk_window_set_position_hint( GdkWindow *window, gint x, gint y ) 
  50   GdkWindowPrivate *priv; 
  51   XSizeHints size_hints; 
  53   g_return_if_fail (window != NULL); 
  55   priv = (GdkWindowPrivate*) window; 
  56   if (priv->destroyed) return; 
  58   size_hints.flags = PPosition; 
  62   XSetWMNormalHints (priv->xdisplay, priv->xwindow, &size_hints); 
  68 //----------------------------------------------------------------------------- 
  70 //----------------------------------------------------------------------------- 
  72 bool gtk_dialog_delete_callback( GtkWidget 
*WXUNUSED(widget
), GdkEvent 
*WXUNUSED(event
), wxDialog 
*win 
) 
  75         wxapp_install_idle_handler(); 
  82 //----------------------------------------------------------------------------- 
  84 //----------------------------------------------------------------------------- 
  86 static void gtk_dialog_size_callback( GtkWidget 
*WXUNUSED(widget
), GtkAllocation
* alloc
, wxDialog 
*win 
) 
  89         wxapp_install_idle_handler(); 
  91     if (!win
->m_hasVMT
) return; 
  93     if ((win
->m_width 
!= alloc
->width
) || (win
->m_height 
!= alloc
->height
)) 
  95         win
->m_width 
= alloc
->width
; 
  96         win
->m_height 
= alloc
->height
; 
 101 //----------------------------------------------------------------------------- 
 103 //----------------------------------------------------------------------------- 
 106 #if (GTK_MINOR_VERSON > 0) 
 107 gtk_dialog_configure_callback( GtkWidget 
*WXUNUSED(widget
), GdkEventConfigure 
*WXUNUSED(event
), wxDialog 
*win 
) 
 109 gtk_dialog_configure_callback( GtkWidget 
*WXUNUSED(widget
), GdkEventConfigure 
*event
, wxDialog 
*win 
) 
 113         wxapp_install_idle_handler(); 
 115     if (!win
->m_hasVMT
) return FALSE
; 
 117 #if (GTK_MINOR_VERSON > 0) 
 120     gdk_window_get_root_origin( win
->m_widget
->window
, &x
, &y 
); 
 128     wxMoveEvent 
mevent( wxPoint(win
->m_x
,win
->m_y
), win
->GetId() ); 
 129     mevent
.SetEventObject( win 
); 
 130     win
->GetEventHandler()->ProcessEvent( mevent 
); 
 135 //----------------------------------------------------------------------------- 
 136 // "realize" from m_widget 
 137 //----------------------------------------------------------------------------- 
 139 /* we cannot MWM hints and icons before the widget has been realized,  
 140    so we do this directly after realization */ 
 143 gtk_dialog_realized_callback( GtkWidget 
*widget
, wxDialog 
*win 
) 
 146         wxapp_install_idle_handler(); 
 148     /* I haven''t been able to set the position of 
 149        the dialog before it is shown, so I set the 
 150        position in "realize" and "map" */ 
 151     gtk_widget_set_uposition( widget
, win
->m_x
, win
->m_y 
); 
 154     gdk_window_set_position_hint( widget->window, win->m_x, win->m_y ); 
 158     if (win
->m_icon 
!= wxNullIcon
) 
 160         wxIcon 
icon( win
->m_icon 
); 
 161         win
->m_icon 
= wxNullIcon
; 
 162         win
->SetIcon( icon 
); 
 168 //----------------------------------------------------------------------------- 
 169 // "map" from m_widget 
 170 //----------------------------------------------------------------------------- 
 173 gtk_dialog_map_callback( GtkWidget 
*widget
, wxDialog 
*win 
) 
 176         wxapp_install_idle_handler(); 
 178     /* I haven''t been able to set the position of 
 179        the dialog before it is shown, so I set the 
 180        position in "realize" and "map" */ 
 181     gtk_widget_set_uposition( widget
, win
->m_x
, win
->m_y 
); 
 183     /* all this is for Motif Window Manager "hints" and is supposed to be 
 184        recognized by other WM as well. not tested. */ 
 185     long decor 
= (long) GDK_DECOR_BORDER
; 
 186     long func 
= (long) GDK_FUNC_MOVE 
; 
 188     if ((win
->GetWindowStyle() & wxCAPTION
) != 0) 
 189         decor 
|= GDK_DECOR_TITLE
; 
 190     if ((win
->GetWindowStyle() & wxSYSTEM_MENU
) != 0) 
 192        decor 
|= GDK_DECOR_MENU
; 
 193        func 
|= GDK_FUNC_CLOSE
; 
 195     if ((win
->GetWindowStyle() & wxMINIMIZE_BOX
) != 0) 
 197         func 
|= GDK_FUNC_MINIMIZE
; 
 198         decor 
|= GDK_DECOR_MINIMIZE
; 
 200     if ((win
->GetWindowStyle() & wxMAXIMIZE_BOX
) != 0) 
 202         decor 
|= GDK_DECOR_MAXIMIZE
; 
 203         func 
|= GDK_FUNC_MAXIMIZE
;            
 205     if ((win
->GetWindowStyle() & wxRESIZE_BORDER
) != 0) 
 207        func 
|= GDK_FUNC_RESIZE
; 
 208        decor 
|= GDK_DECOR_RESIZEH
; 
 210     gdk_window_set_decorations( win
->m_widget
->window
, (GdkWMDecoration
)decor
); 
 211     gdk_window_set_functions( win
->m_widget
->window
, (GdkWMFunction
)func
); 
 213     /* GTK's shrinking/growing policy */ 
 214     if ((win
->GetWindowStyle() & wxRESIZE_BORDER
) == 0) 
 215         gtk_window_set_policy(GTK_WINDOW(win
->m_widget
), 0, 0, 1); 
 217         gtk_window_set_policy(GTK_WINDOW(win
->m_widget
), 1, 1, 1); 
 222 //----------------------------------------------------------------------------- 
 223 // InsertChild for wxDialog 
 224 //----------------------------------------------------------------------------- 
 226 /* Callback for wxFrame. This very strange beast has to be used because 
 227  * C++ has no virtual methods in a constructor. We have to emulate a 
 228  * virtual function here as wxWindows requires different ways to insert 
 229  * a child in container classes. */ 
 231 static void wxInsertChildInDialog( wxDialog
* parent
, wxWindow
* child 
) 
 233     gtk_myfixed_put( GTK_MYFIXED(parent
->m_wxwindow
), 
 234                      GTK_WIDGET(child
->m_widget
), 
 240     if (parent
->HasFlag(wxTAB_TRAVERSAL
)) 
 242         /* we now allow a window to get the focus as long as it 
 243            doesn't have any children. */ 
 244         GTK_WIDGET_UNSET_FLAGS( parent
->m_wxwindow
, GTK_CAN_FOCUS 
); 
 248 //----------------------------------------------------------------------------- 
 250 //----------------------------------------------------------------------------- 
 252 BEGIN_EVENT_TABLE(wxDialog
,wxPanel
) 
 253     EVT_BUTTON  (wxID_OK
,       wxDialog::OnOK
) 
 254     EVT_BUTTON  (wxID_CANCEL
,   wxDialog::OnCancel
) 
 255     EVT_BUTTON  (wxID_APPLY
,    wxDialog::OnApply
) 
 256     EVT_SIZE    (wxDialog::OnSize
) 
 257     EVT_CLOSE   (wxDialog::OnCloseWindow
) 
 260 IMPLEMENT_DYNAMIC_CLASS(wxDialog
,wxPanel
) 
 262 void wxDialog::Init() 
 266     m_modalShowing 
= FALSE
; 
 269 wxDialog::wxDialog( wxWindow 
*parent
, 
 270                     wxWindowID id
, const wxString 
&title
, 
 271                     const wxPoint 
&pos
, const wxSize 
&size
, 
 272                     long style
, const wxString 
&name 
) 
 276     Create( parent
, id
, title
, pos
, size
, style
, name 
); 
 279 bool wxDialog::Create( wxWindow 
*parent
, 
 280                        wxWindowID id
, const wxString 
&title
, 
 281                        const wxPoint 
&pos
, const wxSize 
&size
, 
 282                        long style
, const wxString 
&name 
) 
 284     wxTopLevelWindows
.Append( this ); 
 286     m_needParent 
= FALSE
; 
 288     if (!PreCreation( parent
, pos
, size 
) || 
 289         !CreateBase( parent
, id
, pos
, size
, style
, wxDefaultValidator
, name 
)) 
 291         wxFAIL_MSG( T("wxDialog creation failed") ); 
 295     m_insertCallback 
= (wxInsertChildFunction
) wxInsertChildInDialog
; 
 297     m_widget 
= gtk_window_new( GTK_WINDOW_TOPLEVEL 
); 
 300         gtk_window_set_wmclass( GTK_WINDOW(m_widget
), name
.mb_str(), name
.mb_str() ); 
 302     GTK_WIDGET_UNSET_FLAGS( m_widget
, GTK_CAN_FOCUS 
); 
 304     gtk_signal_connect( GTK_OBJECT(m_widget
), "delete_event", 
 305         GTK_SIGNAL_FUNC(gtk_dialog_delete_callback
), (gpointer
)this ); 
 307     m_wxwindow 
= gtk_myfixed_new(); 
 308     gtk_widget_show( m_wxwindow 
); 
 309     GTK_WIDGET_UNSET_FLAGS( m_wxwindow
, GTK_CAN_FOCUS 
); 
 311     gtk_container_add( GTK_CONTAINER(m_widget
), m_wxwindow 
); 
 315     if (m_parent
) m_parent
->AddChild( this ); 
 319     /*  we cannot set MWM hints  before the widget has 
 320         been realized, so we do this directly after realization */ 
 321     gtk_signal_connect( GTK_OBJECT(m_widget
), "realize", 
 322                         GTK_SIGNAL_FUNC(gtk_dialog_realized_callback
), (gpointer
) this ); 
 324     /* we set the position of the window after the map event. setting it 
 325        before has no effect (with KWM) */ 
 326     gtk_signal_connect( GTK_OBJECT(m_widget
), "map", 
 327                         GTK_SIGNAL_FUNC(gtk_dialog_map_callback
), (gpointer
) this ); 
 329     /* the user resized the frame by dragging etc. */ 
 330     gtk_signal_connect( GTK_OBJECT(m_widget
), "size_allocate", 
 331         GTK_SIGNAL_FUNC(gtk_dialog_size_callback
), (gpointer
)this ); 
 333     gtk_signal_connect( GTK_OBJECT(m_widget
), "configure_event", 
 334         GTK_SIGNAL_FUNC(gtk_dialog_configure_callback
), (gpointer
)this ); 
 339 wxDialog::~wxDialog() 
 341     m_isBeingDeleted 
= TRUE
; 
 343     wxTopLevelWindows
.DeleteObject( this ); 
 345     if (wxTheApp
->GetTopWindow() == this) 
 347         wxTheApp
->SetTopWindow( (wxWindow
*) NULL 
); 
 350     if (wxTopLevelWindows
.Number() == 0) 
 352         wxTheApp
->ExitMainLoop(); 
 356 void wxDialog::SetTitle( const wxString
& title 
) 
 359     if (m_title
.IsNull()) m_title 
= T(""); 
 360     gtk_window_set_title( GTK_WINDOW(m_widget
), m_title
.mbc_str() ); 
 363 wxString 
wxDialog::GetTitle() const 
 365     return (wxString
&)m_title
; 
 368 void wxDialog::OnApply( wxCommandEvent 
&WXUNUSED(event
) ) 
 370     if (Validate()) TransferDataFromWindow(); 
 373 void wxDialog::OnCancel( wxCommandEvent 
&WXUNUSED(event
) ) 
 377         EndModal(wxID_CANCEL
); 
 381         SetReturnCode(wxID_CANCEL
); 
 386 void wxDialog::OnOK( wxCommandEvent 
&WXUNUSED(event
) ) 
 388     if (Validate() && TransferDataFromWindow()) 
 396             SetReturnCode(wxID_OK
); 
 402 void wxDialog::OnPaint( wxPaintEvent
& WXUNUSED(event
) ) 
 407 void wxDialog::OnCloseWindow(wxCloseEvent
& event
) 
 409     // We'll send a Cancel message by default, 
 410     // which may close the dialog. 
 411     // Check for looping if the Cancel event handler calls Close(). 
 413     // Note that if a cancel button and handler aren't present in the dialog, 
 414     // nothing will happen when you close the dialog via the window manager, or 
 416     // We wouldn't want to destroy the dialog by default, since the dialog may have been 
 417     // created on the stack. 
 418     // However, this does mean that calling dialog->Close() won't delete the dialog 
 419     // unless the handler for wxID_CANCEL does so. So use Destroy() if you want to be 
 420     // sure to destroy the dialog. 
 421     // The default OnCancel (above) simply ends a modal dialog, and hides a modeless dialog. 
 423     static wxList s_closing
; 
 425     if (s_closing
.Member(this)) 
 428     s_closing
.Append(this); 
 430     wxCommandEvent 
cancelEvent(wxEVT_COMMAND_BUTTON_CLICKED
, wxID_CANCEL
); 
 431     cancelEvent
.SetEventObject( this ); 
 432     GetEventHandler()->ProcessEvent(cancelEvent
); 
 433     s_closing
.DeleteObject(this); 
 436 bool wxDialog::Destroy() 
 438     if (!wxPendingDelete
.Member(this)) wxPendingDelete
.Append(this); 
 443 void wxDialog::OnSize( wxSizeEvent 
&WXUNUSED(event
) ) 
 445     wxASSERT_MSG( (m_widget 
!= NULL
), T("invalid dialog") ); 
 447 #if wxUSE_CONSTRAINTS 
 453 #endif // wxUSE_CONSTRAINTS 
 455         /* no child: go out ! */ 
 456         if (!GetChildren().First()) return; 
 458         /* do we have exactly one child? */ 
 459         wxWindow 
*child 
= (wxWindow 
*) NULL
; 
 460         for(wxNode 
*node 
= GetChildren().First(); node
; node 
= node
->Next()) 
 462             wxWindow 
*win 
= (wxWindow 
*)node
->Data(); 
 463             if (!wxIS_KIND_OF(win
,wxFrame
) && !wxIS_KIND_OF(win
,wxDialog
)) 
 465                 /* it's the second one: do nothing */ 
 471         /* yes: set it's size to fill all the frame */ 
 472         int client_x
, client_y
; 
 473         GetClientSize( &client_x
, &client_y 
); 
 474         child
->SetSize( 1, 1, client_x
-2, client_y
); 
 478 void wxDialog::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags 
) 
 480     wxASSERT_MSG( (m_widget 
!= NULL
), T("invalid dialog") ); 
 481     wxASSERT_MSG( (m_wxwindow 
!= NULL
), T("invalid dialog") ); 
 483     if (m_resizing
) return; /* I don't like recursions */ 
 488     int old_width 
= m_width
; 
 489     int old_height 
= m_height
; 
 491     if ((sizeFlags 
& wxSIZE_ALLOW_MINUS_ONE
) == 0) 
 493         if (x 
!= -1) m_x 
= x
; 
 494         if (y 
!= -1) m_y 
= y
; 
 495         if (width 
!= -1) m_width 
= width
; 
 496         if (height 
!= -1) m_height 
= height
; 
 506     if ((sizeFlags 
& wxSIZE_AUTO_WIDTH
) == wxSIZE_AUTO_WIDTH
) 
 508         if (width 
== -1) m_width 
= 80; 
 511     if ((sizeFlags 
& wxSIZE_AUTO_HEIGHT
) == wxSIZE_AUTO_HEIGHT
) 
 513        if (height 
== -1) m_height 
= 26; 
 516     if ((m_minWidth 
!= -1) && (m_width 
< m_minWidth
)) m_width 
= m_minWidth
; 
 517     if ((m_minHeight 
!= -1) && (m_height 
< m_minHeight
)) m_height 
= m_minHeight
; 
 518     if ((m_maxWidth 
!= -1) && (m_width 
> m_maxWidth
)) m_width 
= m_maxWidth
; 
 519     if ((m_maxHeight 
!= -1) && (m_height 
> m_maxHeight
)) m_height 
= m_maxHeight
; 
 521     if ((m_x 
!= -1) || (m_y 
!= -1)) 
 523         if ((m_x 
!= old_x
) || (m_y 
!= old_y
)) 
 525             /* we set the position here and when showing the dialog 
 526                for the first time in idle time */ 
 527             gtk_widget_set_uposition( m_widget
, m_x
, m_y 
); 
 531     if ((m_width 
!= old_width
) || (m_height 
!= old_height
)) 
 533         /* actual resizing is deferred to GtkOnSize in idle time and 
 534            when showing the dialog */ 
 541 void wxDialog::GtkOnSize( int WXUNUSED(x
), int WXUNUSED(y
), int width
, int height 
) 
 543     // due to a bug in gtk, x,y are always 0 
 547     if ((m_height 
== height
) && (m_width 
== width
) && (m_sizeSet
)) return; 
 548     if (!m_wxwindow
) return; 
 553     if ((m_minWidth 
!= -1) && (m_width 
< m_minWidth
)) m_width 
= m_minWidth
; 
 554     if ((m_minHeight 
!= -1) && (m_height 
< m_minHeight
)) m_height 
= m_minHeight
; 
 555     if ((m_maxWidth 
!= -1) && (m_width 
> m_maxWidth
)) m_width 
= m_maxWidth
; 
 556     if ((m_maxHeight 
!= -1) && (m_height 
> m_maxHeight
)) m_height 
= m_maxHeight
; 
 558     /* we actually set the size of a frame here and no-where else */ 
 559     gtk_widget_set_usize( m_widget
, m_width
, m_height 
); 
 563     wxSizeEvent 
event( wxSize(m_width
,m_height
), GetId() ); 
 564     event
.SetEventObject( this ); 
 565     GetEventHandler()->ProcessEvent( event 
); 
 568 void wxDialog::Centre( int direction 
) 
 570     wxASSERT_MSG( (m_widget 
!= NULL
), T("invalid dialog") ); 
 575     if ((direction 
& wxHORIZONTAL
) == wxHORIZONTAL
) x 
= (gdk_screen_width () - m_width
) / 2; 
 576     if ((direction 
& wxVERTICAL
) == wxVERTICAL
) y 
= (gdk_screen_height () - m_height
) / 2; 
 581 void wxDialog::OnInternalIdle() 
 583     if (!m_sizeSet 
&& GTK_WIDGET_REALIZED(m_wxwindow
)) 
 584         GtkOnSize( m_x
, m_y
, m_width
, m_height 
); 
 586     wxWindow::OnInternalIdle(); 
 589 bool wxDialog::Show( bool show 
) 
 591     if (!show 
&& IsModal()) 
 593         EndModal( wxID_CANCEL 
); 
 596     if (show 
&& !m_sizeSet
) 
 598         /* by calling GtkOnSize here, we don't have to call 
 599            either after showing the frame, which would entail 
 600            much ugly flicker nor from within the size_allocate 
 601            handler, because GTK 1.1.X forbids that. */ 
 603         GtkOnSize( m_x
, m_y
, m_width
, m_height 
); 
 606     bool ret 
= wxWindow::Show( show 
); 
 608     if (show
) InitDialog(); 
 613 bool wxDialog::IsModal() const 
 615     return m_modalShowing
; 
 618 void wxDialog::SetModal( bool WXUNUSED(flag
) ) 
 622     m_windowStyle |= wxDIALOG_MODAL; 
 624     if (m_windowStyle & wxDIALOG_MODAL) m_windowStyle -= wxDIALOG_MODAL; 
 626     wxFAIL_MSG( T("wxDialog:SetModal obsolete now") ); 
 629 int wxDialog::ShowModal() 
 633        wxFAIL_MSG( T("wxDialog:ShowModal called twice") ); 
 634        return GetReturnCode(); 
 637     wxBusyCursorSuspender cs
; // temporarily suppress the busy cursor 
 641     m_modalShowing 
= TRUE
; 
 643     gtk_grab_add( m_widget 
); 
 645     gtk_grab_remove( m_widget 
); 
 647     return GetReturnCode(); 
 650 void wxDialog::EndModal( int retCode 
) 
 652     SetReturnCode( retCode 
); 
 656         wxFAIL_MSG( T("wxDialog:EndModal called twice") ); 
 660     m_modalShowing 
= FALSE
; 
 667 void wxDialog::InitDialog() 
 669     wxWindow::InitDialog(); 
 672 void wxDialog::SetIcon( const wxIcon 
&icon 
) 
 675     if (!icon
.Ok()) return; 
 677     if (!m_widget
->window
) return; 
 679     wxMask 
*mask 
= icon
.GetMask(); 
 680     GdkBitmap 
*bm 
= (GdkBitmap 
*) NULL
; 
 681     if (mask
) bm 
= mask
->GetBitmap(); 
 683     gdk_window_set_icon( m_widget
->window
, (GdkWindow 
*) NULL
, icon
.GetPixmap(), bm 
);