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