1 ///////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/gtk/popupwin.cpp 
   4 // Author:      Robert Roebling 
   6 // Copyright:   (c) 1998 Robert Roebling 
   7 // Licence:     wxWindows licence 
   8 ///////////////////////////////////////////////////////////////////////////// 
  10 // For compilers that support precompilation, includes "wx.h". 
  11 #include "wx/wxprec.h" 
  15 #include "wx/popupwin.h" 
  20     #include "wx/cursor.h" 
  25 #include <gdk/gdkkeysyms.h> 
  27 #include "wx/gtk/private.h" //for idle stuff 
  28 #include "wx/gtk/win_gtk.h" 
  30 //----------------------------------------------------------------------------- 
  32 //----------------------------------------------------------------------------- 
  35 static gint 
gtk_popup_button_press (GtkWidget 
*widget
, GdkEvent 
*gdk_event
, wxPopupWindow
* win 
) 
  37     GtkWidget 
*child 
= gtk_get_event_widget (gdk_event
); 
  39     /* Ignore events sent out before we connected to the signal */ 
  40     if (win
->m_time 
>= ((GdkEventButton
*)gdk_event
)->time
) 
  43     /*  We don't ask for button press events on the grab widget, so 
  44      *  if an event is reported directly to the grab widget, it must 
  45      *  be on a window outside the application (and thus we remove 
  46      *  the popup window). Otherwise, we check if the widget is a child 
  47      *  of the grab widget, and only remove the popup window if it 
  55             child 
= child
->parent
; 
  59     wxFocusEvent 
event( wxEVT_KILL_FOCUS
, win
->GetId() ); 
  60     event
.SetEventObject( win 
); 
  62     (void)win
->GetEventHandler()->ProcessEvent( event 
); 
  68 //----------------------------------------------------------------------------- 
  69 // "focus" from m_window 
  70 //----------------------------------------------------------------------------- 
  73 static gint 
gtk_dialog_focus_callback( GtkWidget 
*widget
, GtkDirectionType 
WXUNUSED(d
), wxWindow 
*WXUNUSED(win
) ) 
  76         wxapp_install_idle_handler(); 
  78     /* This disables GTK's tab traversal */ 
  79     g_signal_stop_emission_by_name (widget
, "focus"); 
  84 //----------------------------------------------------------------------------- 
  86 //----------------------------------------------------------------------------- 
  89 bool gtk_dialog_delete_callback( GtkWidget 
*WXUNUSED(widget
), GdkEvent 
*WXUNUSED(event
), wxPopupWindow 
*win 
) 
  92         wxapp_install_idle_handler(); 
 101 //----------------------------------------------------------------------------- 
 102 // "realize" from m_widget 
 103 //----------------------------------------------------------------------------- 
 105 /* we cannot MWM hints and icons before the widget has been realized, 
 106    so we do this directly after realization */ 
 110 gtk_dialog_realized_callback( GtkWidget 
* WXUNUSED(widget
), wxPopupWindow 
*win 
) 
 113         wxapp_install_idle_handler(); 
 115     /* all this is for Motif Window Manager "hints" and is supposed to be 
 116        recognized by other WM as well. not tested. */ 
 117     long decor 
= (long) GDK_DECOR_BORDER
; 
 118     long func 
= (long) GDK_FUNC_MOVE 
; 
 120     gdk_window_set_decorations( win
->m_widget
->window
, (GdkWMDecoration
)decor
); 
 121     gdk_window_set_functions( win
->m_widget
->window
, (GdkWMFunction
)func
); 
 123     gtk_window_set_resizable(GTK_WINDOW(win
->m_widget
), FALSE
); 
 129 //----------------------------------------------------------------------------- 
 130 // InsertChild for wxPopupWindow 
 131 //----------------------------------------------------------------------------- 
 133 /* Callback for wxFrame. This very strange beast has to be used because 
 134  * C++ has no virtual methods in a constructor. We have to emulate a 
 135  * virtual function here as wxWidgets requires different ways to insert 
 136  * a child in container classes. */ 
 138 static void wxInsertChildInDialog( wxPopupWindow
* parent
, wxWindow
* child 
) 
 140     gtk_pizza_put( GTK_PIZZA(parent
->m_wxwindow
), 
 141                    GTK_WIDGET(child
->m_widget
), 
 147     if (parent
->HasFlag(wxTAB_TRAVERSAL
)) 
 149         /* we now allow a window to get the focus as long as it 
 150            doesn't have any children. */ 
 151         GTK_WIDGET_UNSET_FLAGS( parent
->m_wxwindow
, GTK_CAN_FOCUS 
); 
 155 //----------------------------------------------------------------------------- 
 157 //----------------------------------------------------------------------------- 
 159 BEGIN_EVENT_TABLE(wxPopupWindow
,wxPopupWindowBase
) 
 160 #ifdef __WXUNIVERSAL__ 
 161     EVT_SIZE(wxPopupWindow::OnSize
) 
 165 wxPopupWindow::~wxPopupWindow() 
 169 bool wxPopupWindow::Create( wxWindow 
*parent
, int style 
) 
 171     m_needParent 
= false; 
 173     if (!PreCreation( parent
, wxDefaultPosition
, wxDefaultSize 
) || 
 174         !CreateBase( parent
, -1, wxDefaultPosition
, wxDefaultSize
, style
, wxDefaultValidator
, wxT("popup") )) 
 176         wxFAIL_MSG( wxT("wxPopupWindow creation failed") ); 
 180     // Unlike windows, top level windows are created hidden by default. 
 183     // All dialogs should really have this style 
 184     m_windowStyle 
|= wxTAB_TRAVERSAL
; 
 186     m_insertCallback 
= (wxInsertChildFunction
) wxInsertChildInDialog
; 
 188     m_widget 
= gtk_window_new( GTK_WINDOW_POPUP 
); 
 190     if ((m_parent
) && (GTK_IS_WINDOW(m_parent
->m_widget
))) 
 191         gtk_window_set_transient_for( GTK_WINDOW(m_widget
), GTK_WINDOW(m_parent
->m_widget
) ); 
 193     GTK_WIDGET_UNSET_FLAGS( m_widget
, GTK_CAN_FOCUS 
); 
 195     g_signal_connect (m_widget
, "delete_event", 
 196                       G_CALLBACK (gtk_dialog_delete_callback
), this); 
 198     m_wxwindow 
= gtk_pizza_new(); 
 199     gtk_widget_show( m_wxwindow 
); 
 200     GTK_WIDGET_UNSET_FLAGS( m_wxwindow
, GTK_CAN_FOCUS 
); 
 202     gtk_container_add( GTK_CONTAINER(m_widget
), m_wxwindow 
); 
 204     if (m_parent
) m_parent
->AddChild( this ); 
 208     /*  we cannot set MWM hints  before the widget has 
 209         been realized, so we do this directly after realization */ 
 210     g_signal_connect (m_widget
, "realize", 
 211                       G_CALLBACK (gtk_dialog_realized_callback
), this); 
 213     // disable native tab traversal 
 214     g_signal_connect (m_widget
, "focus", 
 215                       G_CALLBACK (gtk_dialog_focus_callback
), this); 
 217     m_time 
= gtk_get_current_event_time(); 
 219     g_signal_connect (m_widget
, "button_press_event", 
 220                       G_CALLBACK (gtk_popup_button_press
), this); 
 225 void wxPopupWindow::DoMoveWindow(int WXUNUSED(x
), int WXUNUSED(y
), int WXUNUSED(width
), int WXUNUSED(height
) ) 
 227     wxFAIL_MSG( wxT("DoMoveWindow called for wxPopupWindow") ); 
 230 void wxPopupWindow::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags 
) 
 232     wxASSERT_MSG( (m_widget 
!= NULL
), wxT("invalid dialog") ); 
 233     wxASSERT_MSG( (m_wxwindow 
!= NULL
), wxT("invalid dialog") ); 
 235     if (m_resizing
) return; /* I don't like recursions */ 
 241     int old_width 
= m_width
; 
 242     int old_height 
= m_height
; 
 244     if ((sizeFlags 
& wxSIZE_ALLOW_MINUS_ONE
) == 0) 
 246         if (x 
!= -1) m_x 
= x
; 
 247         if (y 
!= -1) m_y 
= y
; 
 248         if (width 
!= -1) m_width 
= width
; 
 249         if (height 
!= -1) m_height 
= height
; 
 260     if ((sizeFlags & wxSIZE_AUTO_WIDTH) == wxSIZE_AUTO_WIDTH) 
 262         if (width == -1) m_width = 80; 
 265     if ((sizeFlags & wxSIZE_AUTO_HEIGHT) == wxSIZE_AUTO_HEIGHT) 
 267        if (height == -1) m_height = 26; 
 271     int minWidth 
= GetMinWidth(), 
 272         minHeight 
= GetMinHeight(), 
 273         maxWidth 
= GetMaxWidth(), 
 274         maxHeight 
= GetMaxHeight(); 
 276     if ((minWidth 
!= -1) && (m_width 
< minWidth
)) m_width 
= minWidth
; 
 277     if ((minHeight 
!= -1) && (m_height 
< minHeight
)) m_height 
= minHeight
; 
 278     if ((maxWidth 
!= -1) && (m_width 
> maxWidth
)) m_width 
= maxWidth
; 
 279     if ((maxHeight 
!= -1) && (m_height 
> maxHeight
)) m_height 
= maxHeight
; 
 281     if ((m_x 
!= -1) || (m_y 
!= -1)) 
 283         if ((m_x 
!= old_x
) || (m_y 
!= old_y
)) 
 285             /* we set the position here and when showing the dialog 
 286                for the first time in idle time */ 
 287             // Where does that happen in idle time? I do not see it anywhere - MR 
 288             gtk_window_move( GTK_WINDOW(m_widget
), m_x
, m_y 
); 
 292     if ((m_width 
!= old_width
) || (m_height 
!= old_height
)) 
 294         gtk_widget_set_size_request( m_widget
, m_width
, m_height 
); 
 296         /* actual resizing is deferred to GtkOnSize in idle time and 
 297            when showing the dialog */ 
 305 void wxPopupWindow::GtkOnSize( int WXUNUSED(x
), int WXUNUSED(y
), int width
, int height 
) 
 307     // due to a bug in gtk, x,y are always 0 
 311     if ((m_height 
== height
) && (m_width 
== width
) && (m_sizeSet
)) return; 
 312     if (!m_wxwindow
) return; 
 317     /* FIXME: is this a hack? */ 
 318     /* Since for some reason GTK will revert to using maximum size ever set 
 319        for this window, we have to set geometry hints maxsize to match size 
 320        given. Also set the to that minsize since resizing isn't possible 
 324     gint flag 
= GDK_HINT_MAX_SIZE 
| GDK_HINT_MIN_SIZE
; // GDK_HINT_POS; 
 326     geom
.min_width 
= m_width
; 
 327     geom
.min_height 
= m_height
; 
 328     geom
.max_width 
= m_width
; 
 329     geom
.max_height 
= m_height
; 
 330     gtk_window_set_geometry_hints( GTK_WINDOW(m_widget
), 
 333                                    (GdkWindowHints
) flag 
); 
 338     wxSizeEvent 
event( wxSize(m_width
,m_height
), GetId() ); 
 339     event
.SetEventObject( this ); 
 340     GetEventHandler()->ProcessEvent( event 
); 
 343 void wxPopupWindow::OnInternalIdle() 
 345     if (!m_sizeSet 
&& GTK_WIDGET_REALIZED(m_wxwindow
)) 
 346         GtkOnSize( m_x
, m_y
, m_width
, m_height 
); 
 348     wxWindow::OnInternalIdle(); 
 351 bool wxPopupWindow::Show( bool show 
) 
 353     if (show 
&& !m_sizeSet
) 
 355         /* by calling GtkOnSize here, we don't have to call 
 356            either after showing the frame, which would entail 
 357            much ugly flicker nor from within the size_allocate 
 358            handler, because GTK 1.1.X forbids that. */ 
 360         GtkOnSize( m_x
, m_y
, m_width
, m_height 
); 
 363     bool ret 
= wxWindow::Show( show 
); 
 368 #endif // wxUSE_POPUPWIN