1 ///////////////////////////////////////////////////////////////////////////// 
   4 // Author:      Robert Roebling 
   6 // Copyright:   (c) 1998 Robert Roebling 
   7 // Licence:     wxWindows licence 
   8 ///////////////////////////////////////////////////////////////////////////// 
  10 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA) 
  11 #pragma implementation "popupwin.h" 
  14 // For compilers that support precompilation, includes "wx.h". 
  15 #include "wx/wxprec.h" 
  19 #include "wx/popupwin.h" 
  22 #include "wx/cursor.h" 
  26 #include <gdk/gdkkeysyms.h> 
  28 #include "wx/gtk/win_gtk.h" 
  30 //----------------------------------------------------------------------------- 
  32 //----------------------------------------------------------------------------- 
  34 extern void wxapp_install_idle_handler(); 
  37 //----------------------------------------------------------------------------- 
  39 //----------------------------------------------------------------------------- 
  42 static gint 
gtk_popup_button_press (GtkWidget 
*widget
, GdkEvent 
*gdk_event
, wxPopupWindow
* win 
) 
  44     GtkWidget 
*child 
= gtk_get_event_widget (gdk_event
); 
  46   /* We don't ask for button press events on the grab widget, so 
  47    *  if an event is reported directly to the grab widget, it must 
  48    *  be on a window outside the application (and thus we remove 
  49    *  the popup window). Otherwise, we check if the widget is a child 
  50    *  of the grab widget, and only remove the popup window if it 
  59             child 
= child
->parent
; 
  63     wxFocusEvent 
event( wxEVT_KILL_FOCUS
, win
->GetId() ); 
  64     event
.SetEventObject( win 
); 
  66     (void)win
->GetEventHandler()->ProcessEvent( event 
); 
  72 //----------------------------------------------------------------------------- 
  73 // "focus" from m_window 
  74 //----------------------------------------------------------------------------- 
  77 static gint 
gtk_dialog_focus_callback( GtkWidget 
*widget
, GtkDirectionType 
WXUNUSED(d
), wxWindow 
*WXUNUSED(win
) ) 
  80         wxapp_install_idle_handler(); 
  82     // This disables GTK's tab traversal 
  83     gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "focus" ); 
  88 //----------------------------------------------------------------------------- 
  90 //----------------------------------------------------------------------------- 
  93 bool gtk_dialog_delete_callback( GtkWidget 
*WXUNUSED(widget
), GdkEvent 
*WXUNUSED(event
), wxPopupWindow 
*win 
) 
  96         wxapp_install_idle_handler(); 
 105 //----------------------------------------------------------------------------- 
 106 // "realize" from m_widget 
 107 //----------------------------------------------------------------------------- 
 109 /* we cannot MWM hints and icons before the widget has been realized, 
 110    so we do this directly after realization */ 
 114 gtk_dialog_realized_callback( GtkWidget 
* WXUNUSED(widget
), wxPopupWindow 
*win 
) 
 117         wxapp_install_idle_handler(); 
 119     /* all this is for Motif Window Manager "hints" and is supposed to be 
 120        recognized by other WM as well. not tested. */ 
 121     long decor 
= (long) GDK_DECOR_BORDER
; 
 122     long func 
= (long) GDK_FUNC_MOVE 
; 
 124     gdk_window_set_decorations( win
->m_widget
->window
, (GdkWMDecoration
)decor
); 
 125     gdk_window_set_functions( win
->m_widget
->window
, (GdkWMFunction
)func
); 
 127     gtk_window_set_policy(GTK_WINDOW(win
->m_widget
), 0, 0, 1); 
 133 //----------------------------------------------------------------------------- 
 134 // InsertChild for wxPopupWindow 
 135 //----------------------------------------------------------------------------- 
 137 /* Callback for wxFrame. This very strange beast has to be used because 
 138  * C++ has no virtual methods in a constructor. We have to emulate a 
 139  * virtual function here as wxWidgets requires different ways to insert 
 140  * a child in container classes. */ 
 142 static void wxInsertChildInDialog( wxPopupWindow
* parent
, wxWindow
* child 
) 
 144     gtk_pizza_put( GTK_PIZZA(parent
->m_wxwindow
), 
 145                      GTK_WIDGET(child
->m_widget
), 
 151     if (parent
->HasFlag(wxTAB_TRAVERSAL
)) 
 153         /* we now allow a window to get the focus as long as it 
 154            doesn't have any children. */ 
 155         GTK_WIDGET_UNSET_FLAGS( parent
->m_wxwindow
, GTK_CAN_FOCUS 
); 
 159 //----------------------------------------------------------------------------- 
 161 //----------------------------------------------------------------------------- 
 163 BEGIN_EVENT_TABLE(wxPopupWindow
,wxPopupWindowBase
) 
 164 #ifdef __WXUNIVERSAL__ 
 165     EVT_SIZE(wxPopupWindow::OnSize
) 
 169 wxPopupWindow::~wxPopupWindow() 
 173 bool wxPopupWindow::Create( wxWindow 
*parent
, int style 
) 
 175     m_needParent 
= FALSE
; 
 177     if (!PreCreation( parent
, wxDefaultPosition
, wxDefaultSize 
) || 
 178         !CreateBase( parent
, -1, wxDefaultPosition
, wxDefaultSize
, style
, wxDefaultValidator
, wxT("popup") )) 
 180         wxFAIL_MSG( wxT("wxPopupWindow creation failed") ); 
 184     // Unlike windows, top level windows are created hidden by default. 
 187     // All dialogs should really have this style 
 188     m_windowStyle 
|= wxTAB_TRAVERSAL
; 
 190     m_insertCallback 
= (wxInsertChildFunction
) wxInsertChildInDialog
; 
 192     m_widget 
= gtk_window_new( GTK_WINDOW_POPUP 
); 
 194     if ((m_parent
) && (GTK_IS_WINDOW(m_parent
->m_widget
))) 
 195         gtk_window_set_transient_for( GTK_WINDOW(m_widget
), GTK_WINDOW(m_parent
->m_widget
) ); 
 197     GTK_WIDGET_UNSET_FLAGS( m_widget
, GTK_CAN_FOCUS 
); 
 199     gtk_signal_connect( GTK_OBJECT(m_widget
), "delete_event", 
 200         GTK_SIGNAL_FUNC(gtk_dialog_delete_callback
), (gpointer
)this ); 
 202     m_wxwindow 
= gtk_pizza_new(); 
 203     gtk_widget_show( m_wxwindow 
); 
 204     GTK_WIDGET_UNSET_FLAGS( m_wxwindow
, GTK_CAN_FOCUS 
); 
 206     gtk_container_add( GTK_CONTAINER(m_widget
), m_wxwindow 
); 
 208     if (m_parent
) m_parent
->AddChild( this ); 
 212     /*  we cannot set MWM hints  before the widget has 
 213         been realized, so we do this directly after realization */ 
 214     gtk_signal_connect( GTK_OBJECT(m_widget
), "realize", 
 215                         GTK_SIGNAL_FUNC(gtk_dialog_realized_callback
), (gpointer
) this ); 
 217     // disable native tab traversal 
 218     gtk_signal_connect( GTK_OBJECT(m_widget
), "focus", 
 219         GTK_SIGNAL_FUNC(gtk_dialog_focus_callback
), (gpointer
)this ); 
 221     gtk_signal_connect (GTK_OBJECT(m_widget
), "button_press_event", 
 222         GTK_SIGNAL_FUNC(gtk_popup_button_press
), (gpointer
)this ); 
 227 void wxPopupWindow::DoMoveWindow(int WXUNUSED(x
), int WXUNUSED(y
), int WXUNUSED(width
), int WXUNUSED(height
) ) 
 229     wxFAIL_MSG( wxT("DoMoveWindow called for wxPopupWindow") ); 
 232 void wxPopupWindow::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags 
) 
 234     wxASSERT_MSG( (m_widget 
!= NULL
), wxT("invalid dialog") ); 
 235     wxASSERT_MSG( (m_wxwindow 
!= NULL
), wxT("invalid dialog") ); 
 237     if (m_resizing
) return; /* I don't like recursions */ 
 243     int old_width 
= m_width
; 
 244     int old_height 
= m_height
; 
 246     if ((sizeFlags 
& wxSIZE_ALLOW_MINUS_ONE
) == 0) 
 248         if (x 
!= -1) m_x 
= x
; 
 249         if (y 
!= -1) m_y 
= y
; 
 250         if (width 
!= -1) m_width 
= width
; 
 251         if (height 
!= -1) m_height 
= height
; 
 262     if ((sizeFlags & wxSIZE_AUTO_WIDTH) == wxSIZE_AUTO_WIDTH) 
 264         if (width == -1) m_width = 80; 
 267     if ((sizeFlags & wxSIZE_AUTO_HEIGHT) == wxSIZE_AUTO_HEIGHT) 
 269        if (height == -1) m_height = 26; 
 273     int minWidth 
= GetMinWidth(), 
 274         minHeight 
= GetMinHeight(), 
 275         maxWidth 
= GetMaxWidth(), 
 276         maxHeight 
= GetMaxHeight(); 
 278     if ((minWidth 
!= -1) && (m_width 
< minWidth
)) m_width 
= minWidth
; 
 279     if ((minHeight 
!= -1) && (m_height 
< minHeight
)) m_height 
= minHeight
; 
 280     if ((maxWidth 
!= -1) && (m_width 
> maxWidth
)) m_width 
= maxWidth
; 
 281     if ((maxHeight 
!= -1) && (m_height 
> maxHeight
)) m_height 
= maxHeight
; 
 283     if ((m_x 
!= -1) || (m_y 
!= -1)) 
 285         if ((m_x 
!= old_x
) || (m_y 
!= old_y
)) 
 287             /* we set the position here and when showing the dialog 
 288                for the first time in idle time */ 
 289             gtk_widget_set_uposition( m_widget
, m_x
, m_y 
); 
 293     if ((m_width 
!= old_width
) || (m_height 
!= old_height
)) 
 295         gtk_widget_set_usize( m_widget
, m_width
, m_height 
); 
 297         /* actual resizing is deferred to GtkOnSize in idle time and 
 298            when showing the dialog */ 
 306 void wxPopupWindow::GtkOnSize( int WXUNUSED(x
), int WXUNUSED(y
), int width
, int height 
) 
 308     // due to a bug in gtk, x,y are always 0 
 312     if ((m_height 
== height
) && (m_width 
== width
) && (m_sizeSet
)) return; 
 313     if (!m_wxwindow
) return; 
 318     /* FIXME: is this a hack? */ 
 319     /* Since for some reason GTK will revert to using maximum size ever set 
 320        for this window, we have to set geometry hints maxsize to match size 
 321        given. Also set the to that minsize since resizing isn't possible 
 325     gint flag 
= GDK_HINT_MAX_SIZE 
| GDK_HINT_MIN_SIZE
; // GDK_HINT_POS; 
 327     geom
.min_width 
= m_width
; 
 328     geom
.min_height 
= m_height
; 
 329     geom
.max_width 
= m_width
; 
 330     geom
.max_height 
= m_height
; 
 331     gtk_window_set_geometry_hints( GTK_WINDOW(m_widget
), 
 334                                    (GdkWindowHints
) flag 
); 
 339     wxSizeEvent 
event( wxSize(m_width
,m_height
), GetId() ); 
 340     event
.SetEventObject( this ); 
 341     GetEventHandler()->ProcessEvent( event 
); 
 344 void wxPopupWindow::OnInternalIdle() 
 346     if (!m_sizeSet 
&& GTK_WIDGET_REALIZED(m_wxwindow
)) 
 347         GtkOnSize( m_x
, m_y
, m_width
, m_height 
); 
 349     wxWindow::OnInternalIdle(); 
 352 bool wxPopupWindow::Show( bool show 
) 
 354     if (show 
&& !m_sizeSet
) 
 356         /* by calling GtkOnSize here, we don't have to call 
 357            either after showing the frame, which would entail 
 358            much ugly flicker nor from within the size_allocate 
 359            handler, because GTK 1.1.X forbids that. */ 
 361         GtkOnSize( m_x
, m_y
, m_width
, m_height 
); 
 364     bool ret 
= wxWindow::Show( show 
); 
 369 #endif // wxUSE_POPUPWIN