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