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 //-----------------------------------------------------------------------------
70 //-----------------------------------------------------------------------------
73 bool gtk_dialog_delete_callback( GtkWidget
*WXUNUSED(widget
), GdkEvent
*WXUNUSED(event
), wxPopupWindow
*win
)
76 wxapp_install_idle_handler();
85 //-----------------------------------------------------------------------------
86 // "realize" from m_widget
87 //-----------------------------------------------------------------------------
89 /* we cannot MWM hints and icons before the widget has been realized,
90 so we do this directly after realization */
94 gtk_dialog_realized_callback( GtkWidget
* WXUNUSED(widget
), wxPopupWindow
*win
)
97 wxapp_install_idle_handler();
99 /* all this is for Motif Window Manager "hints" and is supposed to be
100 recognized by other WM as well. not tested. */
101 long decor
= (long) GDK_DECOR_BORDER
;
102 long func
= (long) GDK_FUNC_MOVE
;
104 gdk_window_set_decorations( win
->m_widget
->window
, (GdkWMDecoration
)decor
);
105 gdk_window_set_functions( win
->m_widget
->window
, (GdkWMFunction
)func
);
107 gtk_window_set_resizable(GTK_WINDOW(win
->m_widget
), FALSE
);
113 //-----------------------------------------------------------------------------
114 // InsertChild for wxPopupWindow
115 //-----------------------------------------------------------------------------
117 /* Callback for wxFrame. This very strange beast has to be used because
118 * C++ has no virtual methods in a constructor. We have to emulate a
119 * virtual function here as wxWidgets requires different ways to insert
120 * a child in container classes. */
122 static void wxInsertChildInDialog( wxPopupWindow
* parent
, wxWindow
* child
)
124 gtk_pizza_put( GTK_PIZZA(parent
->m_wxwindow
),
125 GTK_WIDGET(child
->m_widget
),
131 if (parent
->HasFlag(wxTAB_TRAVERSAL
))
133 /* we now allow a window to get the focus as long as it
134 doesn't have any children. */
135 GTK_WIDGET_UNSET_FLAGS( parent
->m_wxwindow
, GTK_CAN_FOCUS
);
139 //-----------------------------------------------------------------------------
141 //-----------------------------------------------------------------------------
143 BEGIN_EVENT_TABLE(wxPopupWindow
,wxPopupWindowBase
)
144 #ifdef __WXUNIVERSAL__
145 EVT_SIZE(wxPopupWindow::OnSize
)
149 wxPopupWindow::~wxPopupWindow()
153 bool wxPopupWindow::Create( wxWindow
*parent
, int style
)
155 m_needParent
= false;
157 if (!PreCreation( parent
, wxDefaultPosition
, wxDefaultSize
) ||
158 !CreateBase( parent
, -1, wxDefaultPosition
, wxDefaultSize
, style
, wxDefaultValidator
, wxT("popup") ))
160 wxFAIL_MSG( wxT("wxPopupWindow creation failed") );
164 // Unlike windows, top level windows are created hidden by default.
167 // All dialogs should really have this style
168 m_windowStyle
|= wxTAB_TRAVERSAL
;
170 m_insertCallback
= (wxInsertChildFunction
) wxInsertChildInDialog
;
172 m_widget
= gtk_window_new( GTK_WINDOW_POPUP
);
174 if ((m_parent
) && (GTK_IS_WINDOW(m_parent
->m_widget
)))
175 gtk_window_set_transient_for( GTK_WINDOW(m_widget
), GTK_WINDOW(m_parent
->m_widget
) );
177 GTK_WIDGET_UNSET_FLAGS( m_widget
, GTK_CAN_FOCUS
);
179 g_signal_connect (m_widget
, "delete_event",
180 G_CALLBACK (gtk_dialog_delete_callback
), this);
182 m_wxwindow
= gtk_pizza_new();
183 gtk_widget_show( m_wxwindow
);
184 GTK_WIDGET_UNSET_FLAGS( m_wxwindow
, GTK_CAN_FOCUS
);
186 gtk_container_add( GTK_CONTAINER(m_widget
), m_wxwindow
);
188 if (m_parent
) m_parent
->AddChild( this );
192 /* we cannot set MWM hints before the widget has
193 been realized, so we do this directly after realization */
194 g_signal_connect (m_widget
, "realize",
195 G_CALLBACK (gtk_dialog_realized_callback
), this);
197 m_time
= gtk_get_current_event_time();
199 g_signal_connect (m_widget
, "button_press_event",
200 G_CALLBACK (gtk_popup_button_press
), this);
205 void wxPopupWindow::DoMoveWindow(int WXUNUSED(x
), int WXUNUSED(y
), int WXUNUSED(width
), int WXUNUSED(height
) )
207 wxFAIL_MSG( wxT("DoMoveWindow called for wxPopupWindow") );
210 void wxPopupWindow::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
212 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid dialog") );
213 wxASSERT_MSG( (m_wxwindow
!= NULL
), wxT("invalid dialog") );
215 if (m_resizing
) return; /* I don't like recursions */
221 int old_width
= m_width
;
222 int old_height
= m_height
;
224 if ((sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
) == 0)
226 if (x
!= -1) m_x
= x
;
227 if (y
!= -1) m_y
= y
;
228 if (width
!= -1) m_width
= width
;
229 if (height
!= -1) m_height
= height
;
240 if ((sizeFlags & wxSIZE_AUTO_WIDTH) == wxSIZE_AUTO_WIDTH)
242 if (width == -1) m_width = 80;
245 if ((sizeFlags & wxSIZE_AUTO_HEIGHT) == wxSIZE_AUTO_HEIGHT)
247 if (height == -1) m_height = 26;
251 int minWidth
= GetMinWidth(),
252 minHeight
= GetMinHeight(),
253 maxWidth
= GetMaxWidth(),
254 maxHeight
= GetMaxHeight();
256 if ((minWidth
!= -1) && (m_width
< minWidth
)) m_width
= minWidth
;
257 if ((minHeight
!= -1) && (m_height
< minHeight
)) m_height
= minHeight
;
258 if ((maxWidth
!= -1) && (m_width
> maxWidth
)) m_width
= maxWidth
;
259 if ((maxHeight
!= -1) && (m_height
> maxHeight
)) m_height
= maxHeight
;
261 if ((m_x
!= -1) || (m_y
!= -1))
263 if ((m_x
!= old_x
) || (m_y
!= old_y
))
265 /* we set the position here and when showing the dialog
266 for the first time in idle time */
267 // Where does that happen in idle time? I do not see it anywhere - MR
268 gtk_window_move( GTK_WINDOW(m_widget
), m_x
, m_y
);
272 if ((m_width
!= old_width
) || (m_height
!= old_height
))
274 gtk_widget_set_size_request( m_widget
, m_width
, m_height
);
276 /* actual resizing is deferred to GtkOnSize in idle time and
277 when showing the dialog */
285 void wxPopupWindow::GtkOnSize()
287 if (m_sizeSet
) return;
288 if (!m_wxwindow
) return;
290 /* FIXME: is this a hack? */
291 /* Since for some reason GTK will revert to using maximum size ever set
292 for this window, we have to set geometry hints maxsize to match size
293 given. Also set the to that minsize since resizing isn't possible
297 gint flag
= GDK_HINT_MAX_SIZE
| GDK_HINT_MIN_SIZE
; // GDK_HINT_POS;
299 geom
.min_width
= m_width
;
300 geom
.min_height
= m_height
;
301 geom
.max_width
= m_width
;
302 geom
.max_height
= m_height
;
303 gtk_window_set_geometry_hints( GTK_WINDOW(m_widget
),
306 (GdkWindowHints
) flag
);
311 wxSizeEvent
event( wxSize(m_width
,m_height
), GetId() );
312 event
.SetEventObject( this );
313 GetEventHandler()->ProcessEvent( event
);
316 void wxPopupWindow::OnInternalIdle()
318 if (!m_sizeSet
&& GTK_WIDGET_REALIZED(m_wxwindow
))
321 wxWindow::OnInternalIdle();
324 bool wxPopupWindow::Show( bool show
)
326 if (show
&& !m_sizeSet
)
328 /* by calling GtkOnSize here, we don't have to call
329 either after showing the frame, which would entail
330 much ugly flicker nor from within the size_allocate
331 handler, because GTK 1.1.X forbids that. */
336 bool ret
= wxWindow::Show( show
);
341 #endif // wxUSE_POPUPWIN