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"
22 #include "wx/cursor.h"
26 #include <gdk/gdkkeysyms.h>
28 #include "wx/gtk/private.h" //for idle stuff
29 #include "wx/gtk/win_gtk.h"
31 //-----------------------------------------------------------------------------
33 //-----------------------------------------------------------------------------
36 static gint
gtk_popup_button_press (GtkWidget
*widget
, GdkEvent
*gdk_event
, wxPopupWindow
* win
)
38 GtkWidget
*child
= gtk_get_event_widget (gdk_event
);
40 /* Ignore events sent out before we connected to the signal */
41 if (win
->m_time
>= ((GdkEventButton
*)gdk_event
)->time
)
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
56 child
= child
->parent
;
60 wxFocusEvent
event( wxEVT_KILL_FOCUS
, win
->GetId() );
61 event
.SetEventObject( win
);
63 (void)win
->GetEventHandler()->ProcessEvent( event
);
69 //-----------------------------------------------------------------------------
70 // "focus" from m_window
71 //-----------------------------------------------------------------------------
74 static gint
gtk_dialog_focus_callback( GtkWidget
*widget
, GtkDirectionType
WXUNUSED(d
), wxWindow
*WXUNUSED(win
) )
77 wxapp_install_idle_handler();
79 /* This disables GTK's tab traversal */
80 g_signal_stop_emission_by_name (widget
, "focus");
85 //-----------------------------------------------------------------------------
87 //-----------------------------------------------------------------------------
90 bool gtk_dialog_delete_callback( GtkWidget
*WXUNUSED(widget
), GdkEvent
*WXUNUSED(event
), wxPopupWindow
*win
)
93 wxapp_install_idle_handler();
102 //-----------------------------------------------------------------------------
103 // "realize" from m_widget
104 //-----------------------------------------------------------------------------
106 /* we cannot MWM hints and icons before the widget has been realized,
107 so we do this directly after realization */
111 gtk_dialog_realized_callback( GtkWidget
* WXUNUSED(widget
), wxPopupWindow
*win
)
114 wxapp_install_idle_handler();
116 /* all this is for Motif Window Manager "hints" and is supposed to be
117 recognized by other WM as well. not tested. */
118 long decor
= (long) GDK_DECOR_BORDER
;
119 long func
= (long) GDK_FUNC_MOVE
;
121 gdk_window_set_decorations( win
->m_widget
->window
, (GdkWMDecoration
)decor
);
122 gdk_window_set_functions( win
->m_widget
->window
, (GdkWMFunction
)func
);
124 gtk_window_set_resizable(GTK_WINDOW(win
->m_widget
), FALSE
);
130 //-----------------------------------------------------------------------------
131 // InsertChild for wxPopupWindow
132 //-----------------------------------------------------------------------------
134 /* Callback for wxFrame. This very strange beast has to be used because
135 * C++ has no virtual methods in a constructor. We have to emulate a
136 * virtual function here as wxWidgets requires different ways to insert
137 * a child in container classes. */
139 static void wxInsertChildInDialog( wxPopupWindow
* parent
, wxWindow
* child
)
141 gtk_pizza_put( GTK_PIZZA(parent
->m_wxwindow
),
142 GTK_WIDGET(child
->m_widget
),
148 if (parent
->HasFlag(wxTAB_TRAVERSAL
))
150 /* we now allow a window to get the focus as long as it
151 doesn't have any children. */
152 GTK_WIDGET_UNSET_FLAGS( parent
->m_wxwindow
, GTK_CAN_FOCUS
);
156 //-----------------------------------------------------------------------------
158 //-----------------------------------------------------------------------------
160 BEGIN_EVENT_TABLE(wxPopupWindow
,wxPopupWindowBase
)
161 #ifdef __WXUNIVERSAL__
162 EVT_SIZE(wxPopupWindow::OnSize
)
166 wxPopupWindow::~wxPopupWindow()
170 bool wxPopupWindow::Create( wxWindow
*parent
, int style
)
172 m_needParent
= false;
174 if (!PreCreation( parent
, wxDefaultPosition
, wxDefaultSize
) ||
175 !CreateBase( parent
, -1, wxDefaultPosition
, wxDefaultSize
, style
, wxDefaultValidator
, wxT("popup") ))
177 wxFAIL_MSG( wxT("wxPopupWindow creation failed") );
181 // Unlike windows, top level windows are created hidden by default.
184 // All dialogs should really have this style
185 m_windowStyle
|= wxTAB_TRAVERSAL
;
187 m_insertCallback
= (wxInsertChildFunction
) wxInsertChildInDialog
;
189 m_widget
= gtk_window_new( GTK_WINDOW_POPUP
);
191 if ((m_parent
) && (GTK_IS_WINDOW(m_parent
->m_widget
)))
192 gtk_window_set_transient_for( GTK_WINDOW(m_widget
), GTK_WINDOW(m_parent
->m_widget
) );
194 GTK_WIDGET_UNSET_FLAGS( m_widget
, GTK_CAN_FOCUS
);
196 g_signal_connect (m_widget
, "delete_event",
197 G_CALLBACK (gtk_dialog_delete_callback
), this);
199 m_wxwindow
= gtk_pizza_new();
200 gtk_widget_show( m_wxwindow
);
201 GTK_WIDGET_UNSET_FLAGS( m_wxwindow
, GTK_CAN_FOCUS
);
203 gtk_container_add( GTK_CONTAINER(m_widget
), m_wxwindow
);
205 if (m_parent
) m_parent
->AddChild( this );
209 /* we cannot set MWM hints before the widget has
210 been realized, so we do this directly after realization */
211 g_signal_connect (m_widget
, "realize",
212 G_CALLBACK (gtk_dialog_realized_callback
), this);
214 // disable native tab traversal
215 g_signal_connect (m_widget
, "focus",
216 G_CALLBACK (gtk_dialog_focus_callback
), this);
218 m_time
= gtk_get_current_event_time();
220 g_signal_connect (m_widget
, "button_press_event",
221 G_CALLBACK (gtk_popup_button_press
), this);
226 void wxPopupWindow::DoMoveWindow(int WXUNUSED(x
), int WXUNUSED(y
), int WXUNUSED(width
), int WXUNUSED(height
) )
228 wxFAIL_MSG( wxT("DoMoveWindow called for wxPopupWindow") );
231 void wxPopupWindow::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
233 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid dialog") );
234 wxASSERT_MSG( (m_wxwindow
!= NULL
), wxT("invalid dialog") );
236 if (m_resizing
) return; /* I don't like recursions */
242 int old_width
= m_width
;
243 int old_height
= m_height
;
245 if ((sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
) == 0)
247 if (x
!= -1) m_x
= x
;
248 if (y
!= -1) m_y
= y
;
249 if (width
!= -1) m_width
= width
;
250 if (height
!= -1) m_height
= height
;
261 if ((sizeFlags & wxSIZE_AUTO_WIDTH) == wxSIZE_AUTO_WIDTH)
263 if (width == -1) m_width = 80;
266 if ((sizeFlags & wxSIZE_AUTO_HEIGHT) == wxSIZE_AUTO_HEIGHT)
268 if (height == -1) m_height = 26;
272 int minWidth
= GetMinWidth(),
273 minHeight
= GetMinHeight(),
274 maxWidth
= GetMaxWidth(),
275 maxHeight
= GetMaxHeight();
277 if ((minWidth
!= -1) && (m_width
< minWidth
)) m_width
= minWidth
;
278 if ((minHeight
!= -1) && (m_height
< minHeight
)) m_height
= minHeight
;
279 if ((maxWidth
!= -1) && (m_width
> maxWidth
)) m_width
= maxWidth
;
280 if ((maxHeight
!= -1) && (m_height
> maxHeight
)) m_height
= maxHeight
;
282 if ((m_x
!= -1) || (m_y
!= -1))
284 if ((m_x
!= old_x
) || (m_y
!= old_y
))
286 /* we set the position here and when showing the dialog
287 for the first time in idle time */
288 // Where does that happen in idle time? I do not see it anywhere - MR
289 gtk_window_move( GTK_WINDOW(m_widget
), m_x
, m_y
);
293 if ((m_width
!= old_width
) || (m_height
!= old_height
))
295 gtk_widget_set_size_request( 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