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 */
83 //-----------------------------------------------------------------------------
85 //-----------------------------------------------------------------------------
88 bool gtk_dialog_delete_callback( GtkWidget
*WXUNUSED(widget
), GdkEvent
*WXUNUSED(event
), wxPopupWindow
*win
)
91 wxapp_install_idle_handler();
100 //-----------------------------------------------------------------------------
101 // "realize" from m_widget
102 //-----------------------------------------------------------------------------
104 /* we cannot MWM hints and icons before the widget has been realized,
105 so we do this directly after realization */
109 gtk_dialog_realized_callback( GtkWidget
* WXUNUSED(widget
), wxPopupWindow
*win
)
112 wxapp_install_idle_handler();
114 /* all this is for Motif Window Manager "hints" and is supposed to be
115 recognized by other WM as well. not tested. */
116 long decor
= (long) GDK_DECOR_BORDER
;
117 long func
= (long) GDK_FUNC_MOVE
;
119 gdk_window_set_decorations( win
->m_widget
->window
, (GdkWMDecoration
)decor
);
120 gdk_window_set_functions( win
->m_widget
->window
, (GdkWMFunction
)func
);
122 gtk_window_set_resizable(GTK_WINDOW(win
->m_widget
), FALSE
);
128 //-----------------------------------------------------------------------------
129 // InsertChild for wxPopupWindow
130 //-----------------------------------------------------------------------------
132 /* Callback for wxFrame. This very strange beast has to be used because
133 * C++ has no virtual methods in a constructor. We have to emulate a
134 * virtual function here as wxWidgets requires different ways to insert
135 * a child in container classes. */
137 static void wxInsertChildInDialog( wxPopupWindow
* parent
, wxWindow
* child
)
139 gtk_pizza_put( GTK_PIZZA(parent
->m_wxwindow
),
140 GTK_WIDGET(child
->m_widget
),
146 if (parent
->HasFlag(wxTAB_TRAVERSAL
))
148 /* we now allow a window to get the focus as long as it
149 doesn't have any children. */
150 GTK_WIDGET_UNSET_FLAGS( parent
->m_wxwindow
, GTK_CAN_FOCUS
);
154 //-----------------------------------------------------------------------------
156 //-----------------------------------------------------------------------------
158 BEGIN_EVENT_TABLE(wxPopupWindow
,wxPopupWindowBase
)
159 #ifdef __WXUNIVERSAL__
160 EVT_SIZE(wxPopupWindow::OnSize
)
164 wxPopupWindow::~wxPopupWindow()
168 bool wxPopupWindow::Create( wxWindow
*parent
, int style
)
170 m_needParent
= false;
172 if (!PreCreation( parent
, wxDefaultPosition
, wxDefaultSize
) ||
173 !CreateBase( parent
, -1, wxDefaultPosition
, wxDefaultSize
, style
, wxDefaultValidator
, wxT("popup") ))
175 wxFAIL_MSG( wxT("wxPopupWindow creation failed") );
179 // Unlike windows, top level windows are created hidden by default.
182 // All dialogs should really have this style
183 m_windowStyle
|= wxTAB_TRAVERSAL
;
185 m_insertCallback
= (wxInsertChildFunction
) wxInsertChildInDialog
;
187 m_widget
= gtk_window_new( GTK_WINDOW_POPUP
);
189 if ((m_parent
) && (GTK_IS_WINDOW(m_parent
->m_widget
)))
190 gtk_window_set_transient_for( GTK_WINDOW(m_widget
), GTK_WINDOW(m_parent
->m_widget
) );
192 GTK_WIDGET_UNSET_FLAGS( m_widget
, GTK_CAN_FOCUS
);
194 g_signal_connect (m_widget
, "delete_event",
195 G_CALLBACK (gtk_dialog_delete_callback
), this);
197 m_wxwindow
= gtk_pizza_new();
198 gtk_widget_show( m_wxwindow
);
199 GTK_WIDGET_UNSET_FLAGS( m_wxwindow
, GTK_CAN_FOCUS
);
201 gtk_container_add( GTK_CONTAINER(m_widget
), m_wxwindow
);
203 if (m_parent
) m_parent
->AddChild( this );
207 /* we cannot set MWM hints before the widget has
208 been realized, so we do this directly after realization */
209 g_signal_connect (m_widget
, "realize",
210 G_CALLBACK (gtk_dialog_realized_callback
), this);
212 // disable native tab traversal
213 g_signal_connect (m_widget
, "focus",
214 G_CALLBACK (gtk_dialog_focus_callback
), this);
216 m_time
= gtk_get_current_event_time();
218 g_signal_connect (m_widget
, "button_press_event",
219 G_CALLBACK (gtk_popup_button_press
), this);
224 void wxPopupWindow::DoMoveWindow(int WXUNUSED(x
), int WXUNUSED(y
), int WXUNUSED(width
), int WXUNUSED(height
) )
226 wxFAIL_MSG( wxT("DoMoveWindow called for wxPopupWindow") );
229 void wxPopupWindow::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
231 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid dialog") );
232 wxASSERT_MSG( (m_wxwindow
!= NULL
), wxT("invalid dialog") );
234 if (m_resizing
) return; /* I don't like recursions */
240 int old_width
= m_width
;
241 int old_height
= m_height
;
243 if ((sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
) == 0)
245 if (x
!= -1) m_x
= x
;
246 if (y
!= -1) m_y
= y
;
247 if (width
!= -1) m_width
= width
;
248 if (height
!= -1) m_height
= height
;
259 if ((sizeFlags & wxSIZE_AUTO_WIDTH) == wxSIZE_AUTO_WIDTH)
261 if (width == -1) m_width = 80;
264 if ((sizeFlags & wxSIZE_AUTO_HEIGHT) == wxSIZE_AUTO_HEIGHT)
266 if (height == -1) m_height = 26;
270 int minWidth
= GetMinWidth(),
271 minHeight
= GetMinHeight(),
272 maxWidth
= GetMaxWidth(),
273 maxHeight
= GetMaxHeight();
275 if ((minWidth
!= -1) && (m_width
< minWidth
)) m_width
= minWidth
;
276 if ((minHeight
!= -1) && (m_height
< minHeight
)) m_height
= minHeight
;
277 if ((maxWidth
!= -1) && (m_width
> maxWidth
)) m_width
= maxWidth
;
278 if ((maxHeight
!= -1) && (m_height
> maxHeight
)) m_height
= maxHeight
;
280 if ((m_x
!= -1) || (m_y
!= -1))
282 if ((m_x
!= old_x
) || (m_y
!= old_y
))
284 /* we set the position here and when showing the dialog
285 for the first time in idle time */
286 // Where does that happen in idle time? I do not see it anywhere - MR
287 gtk_window_move( GTK_WINDOW(m_widget
), m_x
, m_y
);
291 if ((m_width
!= old_width
) || (m_height
!= old_height
))
293 gtk_widget_set_size_request( 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()
306 if (m_sizeSet
) return;
307 if (!m_wxwindow
) return;
309 /* FIXME: is this a hack? */
310 /* Since for some reason GTK will revert to using maximum size ever set
311 for this window, we have to set geometry hints maxsize to match size
312 given. Also set the to that minsize since resizing isn't possible
316 gint flag
= GDK_HINT_MAX_SIZE
| GDK_HINT_MIN_SIZE
; // GDK_HINT_POS;
318 geom
.min_width
= m_width
;
319 geom
.min_height
= m_height
;
320 geom
.max_width
= m_width
;
321 geom
.max_height
= m_height
;
322 gtk_window_set_geometry_hints( GTK_WINDOW(m_widget
),
325 (GdkWindowHints
) flag
);
330 wxSizeEvent
event( wxSize(m_width
,m_height
), GetId() );
331 event
.SetEventObject( this );
332 GetEventHandler()->ProcessEvent( event
);
335 void wxPopupWindow::OnInternalIdle()
337 if (!m_sizeSet
&& GTK_WIDGET_REALIZED(m_wxwindow
))
340 wxWindow::OnInternalIdle();
343 bool wxPopupWindow::Show( bool show
)
345 if (show
&& !m_sizeSet
)
347 /* by calling GtkOnSize here, we don't have to call
348 either after showing the frame, which would entail
349 much ugly flicker nor from within the size_allocate
350 handler, because GTK 1.1.X forbids that. */
355 bool ret
= wxWindow::Show( show
);
360 #endif // wxUSE_POPUPWIN