1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/gtk1/popupwin.cpp
4 // Author: Robert Roebling
5 // Copyright: (c) 1998 Robert Roebling
6 // Licence: wxWindows licence
7 /////////////////////////////////////////////////////////////////////////////
9 // For compilers that support precompilation, includes "wx.h".
10 #include "wx/wxprec.h"
14 #include "wx/popupwin.h"
19 #include "wx/cursor.h"
24 #include <gdk/gdkkeysyms.h>
26 #include "wx/gtk1/win_gtk.h"
28 //-----------------------------------------------------------------------------
30 //-----------------------------------------------------------------------------
32 extern void wxapp_install_idle_handler();
35 //-----------------------------------------------------------------------------
37 //-----------------------------------------------------------------------------
40 static gint
gtk_popup_button_press (GtkWidget
*widget
, GdkEvent
*gdk_event
, wxPopupWindow
* win
)
42 GtkWidget
*child
= gtk_get_event_widget (gdk_event
);
44 /* We don't ask for button press events on the grab widget, so
45 * if an event is reported directly to the grab widget, it must
46 * be on a window outside the application (and thus we remove
47 * the popup window). Otherwise, we check if the widget is a child
48 * of the grab widget, and only remove the popup window if it
57 child
= child
->parent
;
61 wxFocusEvent
event( wxEVT_KILL_FOCUS
, win
->GetId() );
62 event
.SetEventObject( win
);
64 (void)win
->HandleWindowEvent( event
);
70 //-----------------------------------------------------------------------------
71 // "focus" from m_window
72 //-----------------------------------------------------------------------------
75 static gint
gtk_dialog_focus_callback( GtkWidget
*widget
, GtkDirectionType
WXUNUSED(d
), wxWindow
*WXUNUSED(win
) )
78 wxapp_install_idle_handler();
80 // This disables GTK's tab traversal
81 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "focus" );
86 //-----------------------------------------------------------------------------
88 //-----------------------------------------------------------------------------
91 bool gtk_dialog_delete_callback( GtkWidget
*WXUNUSED(widget
), GdkEvent
*WXUNUSED(event
), wxPopupWindow
*win
)
94 wxapp_install_idle_handler();
103 //-----------------------------------------------------------------------------
104 // "realize" from m_widget
105 //-----------------------------------------------------------------------------
107 /* we cannot MWM hints and icons before the widget has been realized,
108 so we do this directly after realization */
112 gtk_dialog_realized_callback( GtkWidget
* WXUNUSED(widget
), wxPopupWindow
*win
)
115 wxapp_install_idle_handler();
117 /* all this is for Motif Window Manager "hints" and is supposed to be
118 recognized by other WM as well. not tested. */
119 long decor
= (long) GDK_DECOR_BORDER
;
120 long func
= (long) GDK_FUNC_MOVE
;
122 gdk_window_set_decorations( win
->m_widget
->window
, (GdkWMDecoration
)decor
);
123 gdk_window_set_functions( win
->m_widget
->window
, (GdkWMFunction
)func
);
125 gtk_window_set_policy(GTK_WINDOW(win
->m_widget
), 0, 0, 1);
131 //-----------------------------------------------------------------------------
132 // InsertChild for wxPopupWindow
133 //-----------------------------------------------------------------------------
135 /* Callback for wxFrame. This very strange beast has to be used because
136 * C++ has no virtual methods in a constructor. We have to emulate a
137 * virtual function here as wxWidgets requires different ways to insert
138 * a child in container classes. */
140 static void wxInsertChildInDialog( wxPopupWindow
* parent
, wxWindow
* child
)
142 gtk_pizza_put( GTK_PIZZA(parent
->m_wxwindow
),
143 GTK_WIDGET(child
->m_widget
),
149 if (parent
->HasFlag(wxTAB_TRAVERSAL
))
151 /* we now allow a window to get the focus as long as it
152 doesn't have any children. */
153 GTK_WIDGET_UNSET_FLAGS( parent
->m_wxwindow
, GTK_CAN_FOCUS
);
157 //-----------------------------------------------------------------------------
159 //-----------------------------------------------------------------------------
161 BEGIN_EVENT_TABLE(wxPopupWindow
,wxPopupWindowBase
)
162 #ifdef __WXUNIVERSAL__
163 EVT_SIZE(wxPopupWindow::OnSize
)
167 wxPopupWindow::~wxPopupWindow()
171 bool wxPopupWindow::Create( wxWindow
*parent
, int style
)
173 m_needParent
= false;
175 if (!PreCreation( parent
, wxDefaultPosition
, wxDefaultSize
) ||
176 !CreateBase( parent
, -1, wxDefaultPosition
, wxDefaultSize
, style
, wxDefaultValidator
, wxT("popup") ))
178 wxFAIL_MSG( wxT("wxPopupWindow creation failed") );
182 // Unlike windows, top level windows are created hidden by default.
185 // All dialogs should really have this style
186 m_windowStyle
|= wxTAB_TRAVERSAL
;
188 m_insertCallback
= (wxInsertChildFunction
) wxInsertChildInDialog
;
190 m_widget
= gtk_window_new( GTK_WINDOW_POPUP
);
192 if ((m_parent
) && (GTK_IS_WINDOW(m_parent
->m_widget
)))
193 gtk_window_set_transient_for( GTK_WINDOW(m_widget
), GTK_WINDOW(m_parent
->m_widget
) );
195 GTK_WIDGET_UNSET_FLAGS( m_widget
, GTK_CAN_FOCUS
);
197 gtk_signal_connect( GTK_OBJECT(m_widget
), "delete_event",
198 GTK_SIGNAL_FUNC(gtk_dialog_delete_callback
), (gpointer
)this );
200 m_wxwindow
= gtk_pizza_new();
201 gtk_widget_show( m_wxwindow
);
202 GTK_WIDGET_UNSET_FLAGS( m_wxwindow
, GTK_CAN_FOCUS
);
204 gtk_container_add( GTK_CONTAINER(m_widget
), m_wxwindow
);
206 if (m_parent
) m_parent
->AddChild( this );
210 /* we cannot set MWM hints before the widget has
211 been realized, so we do this directly after realization */
212 gtk_signal_connect( GTK_OBJECT(m_widget
), "realize",
213 GTK_SIGNAL_FUNC(gtk_dialog_realized_callback
), (gpointer
) this );
215 // disable native tab traversal
216 gtk_signal_connect( GTK_OBJECT(m_widget
), "focus",
217 GTK_SIGNAL_FUNC(gtk_dialog_focus_callback
), (gpointer
)this );
219 gtk_signal_connect (GTK_OBJECT(m_widget
), "button_press_event",
220 GTK_SIGNAL_FUNC(gtk_popup_button_press
), (gpointer
)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 gtk_widget_set_uposition( m_widget
, m_x
, m_y
);
291 if ((m_width
!= old_width
) || (m_height
!= old_height
))
293 gtk_widget_set_usize( m_widget
, m_width
, m_height
);
295 /* actual resizing is deferred to GtkOnSize in idle time and
296 when showing the dialog */
304 void wxPopupWindow::GtkOnSize( int WXUNUSED(x
), int WXUNUSED(y
), int width
, int height
)
306 // due to a bug in gtk, x,y are always 0
310 if ((m_height
== height
) && (m_width
== width
) && (m_sizeSet
)) return;
311 if (!m_wxwindow
) return;
316 /* FIXME: is this a hack? */
317 /* Since for some reason GTK will revert to using maximum size ever set
318 for this window, we have to set geometry hints maxsize to match size
319 given. Also set the to that minsize since resizing isn't possible
323 gint flag
= GDK_HINT_MAX_SIZE
| GDK_HINT_MIN_SIZE
; // GDK_HINT_POS;
325 geom
.min_width
= m_width
;
326 geom
.min_height
= m_height
;
327 geom
.max_width
= m_width
;
328 geom
.max_height
= m_height
;
329 gtk_window_set_geometry_hints( GTK_WINDOW(m_widget
),
332 (GdkWindowHints
) flag
);
337 wxSizeEvent
event( wxSize(m_width
,m_height
), GetId() );
338 event
.SetEventObject( this );
339 HandleWindowEvent( event
);
342 void wxPopupWindow::OnInternalIdle()
344 if (!m_sizeSet
&& GTK_WIDGET_REALIZED(m_wxwindow
))
345 GtkOnSize( m_x
, m_y
, m_width
, m_height
);
347 wxWindow::OnInternalIdle();
350 bool wxPopupWindow::Show( bool show
)
352 if (show
&& !m_sizeSet
)
354 /* by calling GtkOnSize here, we don't have to call
355 either after showing the frame, which would entail
356 much ugly flicker nor from within the size_allocate
357 handler, because GTK 1.1.X forbids that. */
359 GtkOnSize( m_x
, m_y
, m_width
, m_height
);
362 bool ret
= wxWindow::Show( show
);
367 #endif // wxUSE_POPUPWIN