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 "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 //-----------------------------------------------------------------------------
67 //-----------------------------------------------------------------------------
70 bool gtk_dialog_delete_callback( GtkWidget
*WXUNUSED(widget
), GdkEvent
*WXUNUSED(event
), wxPopupWindow
*win
)
79 //-----------------------------------------------------------------------------
80 // "realize" from m_widget
81 //-----------------------------------------------------------------------------
83 /* we cannot MWM hints and icons before the widget has been realized,
84 so we do this directly after realization */
88 gtk_dialog_realized_callback( GtkWidget
* WXUNUSED(widget
), wxPopupWindow
*win
)
90 /* all this is for Motif Window Manager "hints" and is supposed to be
91 recognized by other WM as well. not tested. */
92 long decor
= (long) GDK_DECOR_BORDER
;
93 long func
= (long) GDK_FUNC_MOVE
;
95 gdk_window_set_decorations( win
->m_widget
->window
, (GdkWMDecoration
)decor
);
96 gdk_window_set_functions( win
->m_widget
->window
, (GdkWMFunction
)func
);
98 gtk_window_set_resizable(GTK_WINDOW(win
->m_widget
), FALSE
);
104 //-----------------------------------------------------------------------------
105 // InsertChild for wxPopupWindow
106 //-----------------------------------------------------------------------------
108 /* Callback for wxFrame. This very strange beast has to be used because
109 * C++ has no virtual methods in a constructor. We have to emulate a
110 * virtual function here as wxWidgets requires different ways to insert
111 * a child in container classes. */
113 static void wxInsertChildInDialog( wxPopupWindow
* parent
, wxWindow
* child
)
115 gtk_pizza_put( GTK_PIZZA(parent
->m_wxwindow
),
116 GTK_WIDGET(child
->m_widget
),
122 if (parent
->HasFlag(wxTAB_TRAVERSAL
))
124 /* we now allow a window to get the focus as long as it
125 doesn't have any children. */
126 GTK_WIDGET_UNSET_FLAGS( parent
->m_wxwindow
, GTK_CAN_FOCUS
);
130 //-----------------------------------------------------------------------------
132 //-----------------------------------------------------------------------------
134 BEGIN_EVENT_TABLE(wxPopupWindow
,wxPopupWindowBase
)
135 #ifdef __WXUNIVERSAL__
136 EVT_SIZE(wxPopupWindow::OnSize
)
140 wxPopupWindow::~wxPopupWindow()
144 bool wxPopupWindow::Create( wxWindow
*parent
, int style
)
146 m_needParent
= false;
148 if (!PreCreation( parent
, wxDefaultPosition
, wxDefaultSize
) ||
149 !CreateBase( parent
, -1, wxDefaultPosition
, wxDefaultSize
, style
, wxDefaultValidator
, wxT("popup") ))
151 wxFAIL_MSG( wxT("wxPopupWindow creation failed") );
155 // Unlike windows, top level windows are created hidden by default.
158 // All dialogs should really have this style
159 m_windowStyle
|= wxTAB_TRAVERSAL
;
161 m_insertCallback
= (wxInsertChildFunction
) wxInsertChildInDialog
;
163 m_widget
= gtk_window_new( GTK_WINDOW_POPUP
);
165 if ((m_parent
) && (GTK_IS_WINDOW(m_parent
->m_widget
)))
166 gtk_window_set_transient_for( GTK_WINDOW(m_widget
), GTK_WINDOW(m_parent
->m_widget
) );
168 GTK_WIDGET_UNSET_FLAGS( m_widget
, GTK_CAN_FOCUS
);
170 g_signal_connect (m_widget
, "delete_event",
171 G_CALLBACK (gtk_dialog_delete_callback
), this);
173 m_wxwindow
= gtk_pizza_new();
174 gtk_widget_show( m_wxwindow
);
175 GTK_WIDGET_UNSET_FLAGS( m_wxwindow
, GTK_CAN_FOCUS
);
177 gtk_container_add( GTK_CONTAINER(m_widget
), m_wxwindow
);
179 if (m_parent
) m_parent
->AddChild( this );
183 /* we cannot set MWM hints before the widget has
184 been realized, so we do this directly after realization */
185 g_signal_connect (m_widget
, "realize",
186 G_CALLBACK (gtk_dialog_realized_callback
), this);
188 m_time
= gtk_get_current_event_time();
190 g_signal_connect (m_widget
, "button_press_event",
191 G_CALLBACK (gtk_popup_button_press
), this);
196 void wxPopupWindow::DoMoveWindow(int WXUNUSED(x
), int WXUNUSED(y
), int WXUNUSED(width
), int WXUNUSED(height
) )
198 wxFAIL_MSG( wxT("DoMoveWindow called for wxPopupWindow") );
201 void wxPopupWindow::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
203 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid dialog") );
204 wxASSERT_MSG( (m_wxwindow
!= NULL
), wxT("invalid dialog") );
206 if (m_resizing
) return; /* I don't like recursions */
212 int old_width
= m_width
;
213 int old_height
= m_height
;
215 if ((sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
) == 0)
217 if (x
!= -1) m_x
= x
;
218 if (y
!= -1) m_y
= y
;
219 if (width
!= -1) m_width
= width
;
220 if (height
!= -1) m_height
= height
;
231 if ((sizeFlags & wxSIZE_AUTO_WIDTH) == wxSIZE_AUTO_WIDTH)
233 if (width == -1) m_width = 80;
236 if ((sizeFlags & wxSIZE_AUTO_HEIGHT) == wxSIZE_AUTO_HEIGHT)
238 if (height == -1) m_height = 26;
242 int minWidth
= GetMinWidth(),
243 minHeight
= GetMinHeight(),
244 maxWidth
= GetMaxWidth(),
245 maxHeight
= GetMaxHeight();
247 if ((minWidth
!= -1) && (m_width
< minWidth
)) m_width
= minWidth
;
248 if ((minHeight
!= -1) && (m_height
< minHeight
)) m_height
= minHeight
;
249 if ((maxWidth
!= -1) && (m_width
> maxWidth
)) m_width
= maxWidth
;
250 if ((maxHeight
!= -1) && (m_height
> maxHeight
)) m_height
= maxHeight
;
252 if ((m_x
!= -1) || (m_y
!= -1))
254 if ((m_x
!= old_x
) || (m_y
!= old_y
))
256 /* we set the position here and when showing the dialog
257 for the first time in idle time */
258 // Where does that happen in idle time? I do not see it anywhere - MR
259 gtk_window_move( GTK_WINDOW(m_widget
), m_x
, m_y
);
263 if ((m_width
!= old_width
) || (m_height
!= old_height
))
265 gtk_widget_set_size_request( m_widget
, m_width
, m_height
);
267 /* actual resizing is deferred to GtkOnSize in idle time and
268 when showing the dialog */
276 void wxPopupWindow::GtkOnSize()
278 if (m_sizeSet
) return;
279 if (!m_wxwindow
) return;
281 /* FIXME: is this a hack? */
282 /* Since for some reason GTK will revert to using maximum size ever set
283 for this window, we have to set geometry hints maxsize to match size
284 given. Also set the to that minsize since resizing isn't possible
288 gint flag
= GDK_HINT_MAX_SIZE
| GDK_HINT_MIN_SIZE
; // GDK_HINT_POS;
290 geom
.min_width
= m_width
;
291 geom
.min_height
= m_height
;
292 geom
.max_width
= m_width
;
293 geom
.max_height
= m_height
;
294 gtk_window_set_geometry_hints( GTK_WINDOW(m_widget
),
297 (GdkWindowHints
) flag
);
302 wxSizeEvent
event( wxSize(m_width
,m_height
), GetId() );
303 event
.SetEventObject( this );
304 GetEventHandler()->ProcessEvent( event
);
307 void wxPopupWindow::OnInternalIdle()
309 if (!m_sizeSet
&& GTK_WIDGET_REALIZED(m_wxwindow
))
312 wxWindow::OnInternalIdle();
315 bool wxPopupWindow::Show( bool show
)
317 if (show
&& !m_sizeSet
)
319 /* by calling GtkOnSize here, we don't have to call
320 either after showing the frame, which would entail
321 much ugly flicker nor from within the size_allocate
322 handler, because GTK 1.1.X forbids that. */
327 bool ret
= wxWindow::Show( show
);
332 #endif // wxUSE_POPUPWIN