]> git.saurik.com Git - wxWidgets.git/blame - src/gtk/popupwin.cpp
Only send keypress events to focus widget, not its parents
[wxWidgets.git] / src / gtk / popupwin.cpp
CommitLineData
9f41d601 1/////////////////////////////////////////////////////////////////////////////
670f9935 2// Name: src/gtk/popupwin.cpp
9f41d601
RR
3// Purpose:
4// Author: Robert Roebling
5// Id: $Id$
6// Copyright: (c) 1998 Robert Roebling
65571936 7// Licence: wxWindows licence
9f41d601
RR
8/////////////////////////////////////////////////////////////////////////////
9
14f355c2
VS
10// For compilers that support precompilation, includes "wx.h".
11#include "wx/wxprec.h"
f3ecfad1
VS
12
13#if wxUSE_POPUPWIN
14
9f41d601 15#include "wx/popupwin.h"
670f9935
WS
16
17#ifndef WX_PRECOMP
18 #include "wx/app.h"
76b49cf4 19 #include "wx/frame.h"
c8326d64 20 #include "wx/cursor.h"
670f9935
WS
21#endif // WX_PRECOMP
22
9f41d601 23#include <gtk/gtk.h>
9f41d601
RR
24
25#include "wx/gtk/win_gtk.h"
26
f7204798
RR
27//-----------------------------------------------------------------------------
28// "button_press"
29//-----------------------------------------------------------------------------
30
865bb325 31extern "C" {
f7204798
RR
32static gint gtk_popup_button_press (GtkWidget *widget, GdkEvent *gdk_event, wxPopupWindow* win )
33{
34 GtkWidget *child = gtk_get_event_widget (gdk_event);
35
33c0d0ed
RR
36 /* Ignore events sent out before we connected to the signal */
37 if (win->m_time >= ((GdkEventButton*)gdk_event)->time)
38 return FALSE;
39
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
45 * is not. */
f7204798
RR
46 if (child != widget)
47 {
48 while (child)
88d19775
MR
49 {
50 if (child == widget)
51 return FALSE;
f7204798
RR
52 child = child->parent;
53 }
54 }
55
56 wxFocusEvent event( wxEVT_KILL_FOCUS, win->GetId() );
57 event.SetEventObject( win );
58
59 (void)win->GetEventHandler()->ProcessEvent( event );
60
61 return TRUE;
62}
865bb325 63}
f7204798 64
9f41d601
RR
65//-----------------------------------------------------------------------------
66// "delete_event"
67//-----------------------------------------------------------------------------
68
865bb325 69extern "C" {
9f41d601
RR
70bool gtk_dialog_delete_callback( GtkWidget *WXUNUSED(widget), GdkEvent *WXUNUSED(event), wxPopupWindow *win )
71{
9f41d601
RR
72 if (win->IsEnabled())
73 win->Close();
74
75 return TRUE;
76}
865bb325 77}
9f41d601 78
9f41d601
RR
79//-----------------------------------------------------------------------------
80// "realize" from m_widget
81//-----------------------------------------------------------------------------
82
83/* we cannot MWM hints and icons before the widget has been realized,
84 so we do this directly after realization */
85
865bb325 86extern "C" {
9f41d601
RR
87static gint
88gtk_dialog_realized_callback( GtkWidget * WXUNUSED(widget), wxPopupWindow *win )
89{
9f41d601
RR
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 ;
94
95 gdk_window_set_decorations( win->m_widget->window, (GdkWMDecoration)decor);
96 gdk_window_set_functions( win->m_widget->window, (GdkWMFunction)func);
97
43a52404 98 gtk_window_set_resizable(GTK_WINDOW(win->m_widget), FALSE);
9f41d601
RR
99
100 return FALSE;
101}
865bb325 102}
9f41d601
RR
103
104//-----------------------------------------------------------------------------
105// InsertChild for wxPopupWindow
106//-----------------------------------------------------------------------------
107
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
77ffb593 110 * virtual function here as wxWidgets requires different ways to insert
9f41d601
RR
111 * a child in container classes. */
112
7a3ba5af 113static void wxInsertChildInPopupWin(wxWindowGTK* parent, wxWindowGTK* child)
9f41d601
RR
114{
115 gtk_pizza_put( GTK_PIZZA(parent->m_wxwindow),
10bd1f7d 116 child->m_widget,
88d19775
MR
117 child->m_x,
118 child->m_y,
119 child->m_width,
120 child->m_height );
9f41d601
RR
121
122 if (parent->HasFlag(wxTAB_TRAVERSAL))
123 {
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 );
127 }
128}
129
130//-----------------------------------------------------------------------------
131// wxPopupWindow
132//-----------------------------------------------------------------------------
133
8f0db49c
VS
134BEGIN_EVENT_TABLE(wxPopupWindow,wxPopupWindowBase)
135#ifdef __WXUNIVERSAL__
6522713c 136 EVT_SIZE(wxPopupWindow::OnSize)
8f0db49c 137#endif
9f41d601
RR
138END_EVENT_TABLE()
139
ad9fb033
RR
140wxPopupWindow::~wxPopupWindow()
141{
ad9fb033
RR
142}
143
9f41d601
RR
144bool wxPopupWindow::Create( wxWindow *parent, int style )
145{
ab7eba4c
PC
146 m_sizeSet = false;
147
9f41d601 148 if (!PreCreation( parent, wxDefaultPosition, wxDefaultSize ) ||
2b5f62a0 149 !CreateBase( parent, -1, wxDefaultPosition, wxDefaultSize, style, wxDefaultValidator, wxT("popup") ))
9f41d601
RR
150 {
151 wxFAIL_MSG( wxT("wxPopupWindow creation failed") );
670f9935 152 return false;
9f41d601
RR
153 }
154
da19de36
RR
155 // Unlike windows, top level windows are created hidden by default.
156 m_isShown = false;
88d19775 157
9f41d601
RR
158 // All dialogs should really have this style
159 m_windowStyle |= wxTAB_TRAVERSAL;
160
c821db16 161 m_insertCallback = wxInsertChildInPopupWin;
9f41d601
RR
162
163 m_widget = gtk_window_new( GTK_WINDOW_POPUP );
164
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) );
167
168 GTK_WIDGET_UNSET_FLAGS( m_widget, GTK_CAN_FOCUS );
169
9fa72bd2
MR
170 g_signal_connect (m_widget, "delete_event",
171 G_CALLBACK (gtk_dialog_delete_callback), this);
9f41d601
RR
172
173 m_wxwindow = gtk_pizza_new();
174 gtk_widget_show( m_wxwindow );
175 GTK_WIDGET_UNSET_FLAGS( m_wxwindow, GTK_CAN_FOCUS );
176
177 gtk_container_add( GTK_CONTAINER(m_widget), m_wxwindow );
178
179 if (m_parent) m_parent->AddChild( this );
180
181 PostCreation();
182
183 /* we cannot set MWM hints before the widget has
184 been realized, so we do this directly after realization */
9fa72bd2
MR
185 g_signal_connect (m_widget, "realize",
186 G_CALLBACK (gtk_dialog_realized_callback), this);
9f41d601 187
33c0d0ed
RR
188 m_time = gtk_get_current_event_time();
189
9fa72bd2
MR
190 g_signal_connect (m_widget, "button_press_event",
191 G_CALLBACK (gtk_popup_button_press), this);
88d19775 192
670f9935 193 return true;
9f41d601
RR
194}
195
196void wxPopupWindow::DoMoveWindow(int WXUNUSED(x), int WXUNUSED(y), int WXUNUSED(width), int WXUNUSED(height) )
197{
198 wxFAIL_MSG( wxT("DoMoveWindow called for wxPopupWindow") );
199}
200
201void wxPopupWindow::DoSetSize( int x, int y, int width, int height, int sizeFlags )
202{
203 wxASSERT_MSG( (m_widget != NULL), wxT("invalid dialog") );
204 wxASSERT_MSG( (m_wxwindow != NULL), wxT("invalid dialog") );
205
206 if (m_resizing) return; /* I don't like recursions */
670f9935 207 m_resizing = true;
9f41d601
RR
208
209 int old_x = m_x;
210 int old_y = m_y;
211
212 int old_width = m_width;
213 int old_height = m_height;
214
215 if ((sizeFlags & wxSIZE_ALLOW_MINUS_ONE) == 0)
216 {
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;
221 }
222 else
223 {
224 m_x = x;
225 m_y = y;
226 m_width = width;
227 m_height = height;
228 }
229
230/*
231 if ((sizeFlags & wxSIZE_AUTO_WIDTH) == wxSIZE_AUTO_WIDTH)
232 {
233 if (width == -1) m_width = 80;
234 }
235
236 if ((sizeFlags & wxSIZE_AUTO_HEIGHT) == wxSIZE_AUTO_HEIGHT)
237 {
238 if (height == -1) m_height = 26;
239 }
240*/
241
82008f15 242 ConstrainSize();
9f41d601
RR
243
244 if ((m_x != -1) || (m_y != -1))
245 {
246 if ((m_x != old_x) || (m_y != old_y))
247 {
248 /* we set the position here and when showing the dialog
249 for the first time in idle time */
cd6645a2
MR
250 // Where does that happen in idle time? I do not see it anywhere - MR
251 gtk_window_move( GTK_WINDOW(m_widget), m_x, m_y );
9f41d601
RR
252 }
253 }
254
255 if ((m_width != old_width) || (m_height != old_height))
256 {
370dc79c 257 gtk_widget_set_size_request( m_widget, m_width, m_height );
9f41d601
RR
258
259 /* actual resizing is deferred to GtkOnSize in idle time and
260 when showing the dialog */
670f9935 261 m_sizeSet = false;
9f41d601
RR
262
263 }
264
670f9935 265 m_resizing = false;
9f41d601
RR
266}
267
b5e31cc8 268void wxPopupWindow::GtkOnSize()
9f41d601 269{
b5e31cc8 270 if (m_sizeSet) return;
9f41d601
RR
271 if (!m_wxwindow) return;
272
ef00dc09 273 /* FIXME: is this a hack? */
7e027698
RR
274 /* Since for some reason GTK will revert to using maximum size ever set
275 for this window, we have to set geometry hints maxsize to match size
276 given. Also set the to that minsize since resizing isn't possible
277 anyway. */
9f41d601
RR
278
279 /* set size hints */
7e027698 280 gint flag = GDK_HINT_MAX_SIZE | GDK_HINT_MIN_SIZE; // GDK_HINT_POS;
9f41d601 281 GdkGeometry geom;
7e027698
RR
282 geom.min_width = m_width;
283 geom.min_height = m_height;
ef00dc09
RR
284 geom.max_width = m_width;
285 geom.max_height = m_height;
9f41d601
RR
286 gtk_window_set_geometry_hints( GTK_WINDOW(m_widget),
287 (GtkWidget*) NULL,
288 &geom,
289 (GdkWindowHints) flag );
290
ef00dc09 291
670f9935 292 m_sizeSet = true;
9f41d601
RR
293
294 wxSizeEvent event( wxSize(m_width,m_height), GetId() );
295 event.SetEventObject( this );
296 GetEventHandler()->ProcessEvent( event );
297}
298
299void wxPopupWindow::OnInternalIdle()
300{
301 if (!m_sizeSet && GTK_WIDGET_REALIZED(m_wxwindow))
b5e31cc8 302 GtkOnSize();
9f41d601
RR
303
304 wxWindow::OnInternalIdle();
305}
306
307bool wxPopupWindow::Show( bool show )
308{
309 if (show && !m_sizeSet)
310 {
311 /* by calling GtkOnSize here, we don't have to call
312 either after showing the frame, which would entail
313 much ugly flicker nor from within the size_allocate
314 handler, because GTK 1.1.X forbids that. */
315
b5e31cc8 316 GtkOnSize();
9f41d601 317 }
88d19775 318
9f41d601 319 bool ret = wxWindow::Show( show );
88d19775 320
9f41d601
RR
321 return ret;
322}
323
f3ecfad1 324#endif // wxUSE_POPUPWIN