1 ///////////////////////////////////////////////////////////////////////////// 
   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" 
  18 #include "wx/cursor.h" 
  22 #include <gdk/gdkkeysyms.h> 
  24 #include "wx/gtk/private.h" //for idle stuff 
  25 #include "wx/gtk/win_gtk.h" 
  27 //----------------------------------------------------------------------------- 
  29 //----------------------------------------------------------------------------- 
  32 static gint 
gtk_popup_button_press (GtkWidget 
*widget
, GdkEvent 
*gdk_event
, wxPopupWindow
* win 
) 
  34     GtkWidget 
*child 
= gtk_get_event_widget (gdk_event
); 
  36     /* Ignore events sent out before we connected to the signal */ 
  37     if (win
->m_time 
>= ((GdkEventButton
*)gdk_event
)->time
) 
  40     /*  We don't ask for button press events on the grab widget, so 
  41      *  if an event is reported directly to the grab widget, it must 
  42      *  be on a window outside the application (and thus we remove 
  43      *  the popup window). Otherwise, we check if the widget is a child 
  44      *  of the grab widget, and only remove the popup window if it 
  52             child 
= child
->parent
; 
  56     wxFocusEvent 
event( wxEVT_KILL_FOCUS
, win
->GetId() ); 
  57     event
.SetEventObject( win 
); 
  59     (void)win
->GetEventHandler()->ProcessEvent( event 
); 
  65 //----------------------------------------------------------------------------- 
  66 // "focus" from m_window 
  67 //----------------------------------------------------------------------------- 
  70 static gint 
gtk_dialog_focus_callback( GtkWidget 
*widget
, GtkDirectionType 
WXUNUSED(d
), wxWindow 
*WXUNUSED(win
) ) 
  73         wxapp_install_idle_handler(); 
  75     /* This disables GTK's tab traversal */ 
  76     g_signal_stop_emission_by_name (widget
, "focus"); 
  81 //----------------------------------------------------------------------------- 
  83 //----------------------------------------------------------------------------- 
  86 bool gtk_dialog_delete_callback( GtkWidget 
*WXUNUSED(widget
), GdkEvent 
*WXUNUSED(event
), wxPopupWindow 
*win 
) 
  89         wxapp_install_idle_handler(); 
  98 //----------------------------------------------------------------------------- 
  99 // "realize" from m_widget 
 100 //----------------------------------------------------------------------------- 
 102 /* we cannot MWM hints and icons before the widget has been realized, 
 103    so we do this directly after realization */ 
 107 gtk_dialog_realized_callback( GtkWidget 
* WXUNUSED(widget
), wxPopupWindow 
*win 
) 
 110         wxapp_install_idle_handler(); 
 112     /* all this is for Motif Window Manager "hints" and is supposed to be 
 113        recognized by other WM as well. not tested. */ 
 114     long decor 
= (long) GDK_DECOR_BORDER
; 
 115     long func 
= (long) GDK_FUNC_MOVE 
; 
 117     gdk_window_set_decorations( win
->m_widget
->window
, (GdkWMDecoration
)decor
); 
 118     gdk_window_set_functions( win
->m_widget
->window
, (GdkWMFunction
)func
); 
 120     gtk_window_set_resizable(GTK_WINDOW(win
->m_widget
), FALSE
); 
 126 //----------------------------------------------------------------------------- 
 127 // InsertChild for wxPopupWindow 
 128 //----------------------------------------------------------------------------- 
 130 /* Callback for wxFrame. This very strange beast has to be used because 
 131  * C++ has no virtual methods in a constructor. We have to emulate a 
 132  * virtual function here as wxWidgets requires different ways to insert 
 133  * a child in container classes. */ 
 135 static void wxInsertChildInDialog( wxPopupWindow
* parent
, wxWindow
* child 
) 
 137     gtk_pizza_put( GTK_PIZZA(parent
->m_wxwindow
), 
 138                    GTK_WIDGET(child
->m_widget
), 
 144     if (parent
->HasFlag(wxTAB_TRAVERSAL
)) 
 146         /* we now allow a window to get the focus as long as it 
 147            doesn't have any children. */ 
 148         GTK_WIDGET_UNSET_FLAGS( parent
->m_wxwindow
, GTK_CAN_FOCUS 
); 
 152 //----------------------------------------------------------------------------- 
 154 //----------------------------------------------------------------------------- 
 156 BEGIN_EVENT_TABLE(wxPopupWindow
,wxPopupWindowBase
) 
 157 #ifdef __WXUNIVERSAL__ 
 158     EVT_SIZE(wxPopupWindow::OnSize
) 
 162 wxPopupWindow::~wxPopupWindow() 
 166 bool wxPopupWindow::Create( wxWindow 
*parent
, int style 
) 
 168     m_needParent 
= FALSE
; 
 170     if (!PreCreation( parent
, wxDefaultPosition
, wxDefaultSize 
) || 
 171         !CreateBase( parent
, -1, wxDefaultPosition
, wxDefaultSize
, style
, wxDefaultValidator
, wxT("popup") )) 
 173         wxFAIL_MSG( wxT("wxPopupWindow creation failed") ); 
 177     // Unlike windows, top level windows are created hidden by default. 
 180     // All dialogs should really have this style 
 181     m_windowStyle 
|= wxTAB_TRAVERSAL
; 
 183     m_insertCallback 
= (wxInsertChildFunction
) wxInsertChildInDialog
; 
 185     m_widget 
= gtk_window_new( GTK_WINDOW_POPUP 
); 
 187     if ((m_parent
) && (GTK_IS_WINDOW(m_parent
->m_widget
))) 
 188         gtk_window_set_transient_for( GTK_WINDOW(m_widget
), GTK_WINDOW(m_parent
->m_widget
) ); 
 190     GTK_WIDGET_UNSET_FLAGS( m_widget
, GTK_CAN_FOCUS 
); 
 192     g_signal_connect (m_widget
, "delete_event", 
 193                       G_CALLBACK (gtk_dialog_delete_callback
), this); 
 195     m_wxwindow 
= gtk_pizza_new(); 
 196     gtk_widget_show( m_wxwindow 
); 
 197     GTK_WIDGET_UNSET_FLAGS( m_wxwindow
, GTK_CAN_FOCUS 
); 
 199     gtk_container_add( GTK_CONTAINER(m_widget
), m_wxwindow 
); 
 201     if (m_parent
) m_parent
->AddChild( this ); 
 205     /*  we cannot set MWM hints  before the widget has 
 206         been realized, so we do this directly after realization */ 
 207     g_signal_connect (m_widget
, "realize", 
 208                       G_CALLBACK (gtk_dialog_realized_callback
), this); 
 210     // disable native tab traversal 
 211     g_signal_connect (m_widget
, "focus", 
 212                       G_CALLBACK (gtk_dialog_focus_callback
), this); 
 214     m_time 
= gtk_get_current_event_time(); 
 216     g_signal_connect (m_widget
, "button_press_event", 
 217                       G_CALLBACK (gtk_popup_button_press
), this); 
 222 void wxPopupWindow::DoMoveWindow(int WXUNUSED(x
), int WXUNUSED(y
), int WXUNUSED(width
), int WXUNUSED(height
) ) 
 224     wxFAIL_MSG( wxT("DoMoveWindow called for wxPopupWindow") ); 
 227 void wxPopupWindow::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags 
) 
 229     wxASSERT_MSG( (m_widget 
!= NULL
), wxT("invalid dialog") ); 
 230     wxASSERT_MSG( (m_wxwindow 
!= NULL
), wxT("invalid dialog") ); 
 232     if (m_resizing
) return; /* I don't like recursions */ 
 238     int old_width 
= m_width
; 
 239     int old_height 
= m_height
; 
 241     if ((sizeFlags 
& wxSIZE_ALLOW_MINUS_ONE
) == 0) 
 243         if (x 
!= -1) m_x 
= x
; 
 244         if (y 
!= -1) m_y 
= y
; 
 245         if (width 
!= -1) m_width 
= width
; 
 246         if (height 
!= -1) m_height 
= height
; 
 257     if ((sizeFlags & wxSIZE_AUTO_WIDTH) == wxSIZE_AUTO_WIDTH) 
 259         if (width == -1) m_width = 80; 
 262     if ((sizeFlags & wxSIZE_AUTO_HEIGHT) == wxSIZE_AUTO_HEIGHT) 
 264        if (height == -1) m_height = 26; 
 268     int minWidth 
= GetMinWidth(), 
 269         minHeight 
= GetMinHeight(), 
 270         maxWidth 
= GetMaxWidth(), 
 271         maxHeight 
= GetMaxHeight(); 
 273     if ((minWidth 
!= -1) && (m_width 
< minWidth
)) m_width 
= minWidth
; 
 274     if ((minHeight 
!= -1) && (m_height 
< minHeight
)) m_height 
= minHeight
; 
 275     if ((maxWidth 
!= -1) && (m_width 
> maxWidth
)) m_width 
= maxWidth
; 
 276     if ((maxHeight 
!= -1) && (m_height 
> maxHeight
)) m_height 
= maxHeight
; 
 278     if ((m_x 
!= -1) || (m_y 
!= -1)) 
 280         if ((m_x 
!= old_x
) || (m_y 
!= old_y
)) 
 282             /* we set the position here and when showing the dialog 
 283                for the first time in idle time */ 
 284             // Where does that happen in idle time? I do not see it anywhere - MR 
 285             gtk_window_move( GTK_WINDOW(m_widget
), m_x
, m_y 
); 
 289     if ((m_width 
!= old_width
) || (m_height 
!= old_height
)) 
 291         gtk_widget_set_size_request( m_widget
, m_width
, m_height 
); 
 293         /* actual resizing is deferred to GtkOnSize in idle time and 
 294            when showing the dialog */ 
 302 void wxPopupWindow::GtkOnSize( int WXUNUSED(x
), int WXUNUSED(y
), int width
, int height 
) 
 304     // due to a bug in gtk, x,y are always 0 
 308     if ((m_height 
== height
) && (m_width 
== width
) && (m_sizeSet
)) return; 
 309     if (!m_wxwindow
) return; 
 314     /* FIXME: is this a hack? */ 
 315     /* Since for some reason GTK will revert to using maximum size ever set 
 316        for this window, we have to set geometry hints maxsize to match size 
 317        given. Also set the to that minsize since resizing isn't possible 
 321     gint flag 
= GDK_HINT_MAX_SIZE 
| GDK_HINT_MIN_SIZE
; // GDK_HINT_POS; 
 323     geom
.min_width 
= m_width
; 
 324     geom
.min_height 
= m_height
; 
 325     geom
.max_width 
= m_width
; 
 326     geom
.max_height 
= m_height
; 
 327     gtk_window_set_geometry_hints( GTK_WINDOW(m_widget
), 
 330                                    (GdkWindowHints
) flag 
); 
 335     wxSizeEvent 
event( wxSize(m_width
,m_height
), GetId() ); 
 336     event
.SetEventObject( this ); 
 337     GetEventHandler()->ProcessEvent( event 
); 
 340 void wxPopupWindow::OnInternalIdle() 
 342     if (!m_sizeSet 
&& GTK_WIDGET_REALIZED(m_wxwindow
)) 
 343         GtkOnSize( m_x
, m_y
, m_width
, m_height 
); 
 345     wxWindow::OnInternalIdle(); 
 348 bool wxPopupWindow::Show( bool show 
) 
 350     if (show 
&& !m_sizeSet
) 
 352         /* by calling GtkOnSize here, we don't have to call 
 353            either after showing the frame, which would entail 
 354            much ugly flicker nor from within the size_allocate 
 355            handler, because GTK 1.1.X forbids that. */ 
 357         GtkOnSize( m_x
, m_y
, m_width
, m_height 
); 
 360     bool ret 
= wxWindow::Show( show 
); 
 365 #endif // wxUSE_POPUPWIN