]> git.saurik.com Git - wxWidgets.git/blame - src/gtk/popupwin.cpp
[ 1509599 ] 'Split pickers page in widgets sample' with more icons and rebaking.
[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
RR
23#include <gdk/gdk.h>
24#include <gtk/gtk.h>
25#include <gdk/gdkkeysyms.h>
26
84833214 27#include "wx/gtk/private.h" //for idle stuff
9f41d601
RR
28#include "wx/gtk/win_gtk.h"
29
f7204798
RR
30//-----------------------------------------------------------------------------
31// "button_press"
32//-----------------------------------------------------------------------------
33
865bb325 34extern "C" {
f7204798
RR
35static gint gtk_popup_button_press (GtkWidget *widget, GdkEvent *gdk_event, wxPopupWindow* win )
36{
37 GtkWidget *child = gtk_get_event_widget (gdk_event);
38
33c0d0ed
RR
39 /* Ignore events sent out before we connected to the signal */
40 if (win->m_time >= ((GdkEventButton*)gdk_event)->time)
41 return FALSE;
42
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
48 * is not. */
f7204798
RR
49 if (child != widget)
50 {
51 while (child)
88d19775
MR
52 {
53 if (child == widget)
54 return FALSE;
f7204798
RR
55 child = child->parent;
56 }
57 }
58
59 wxFocusEvent event( wxEVT_KILL_FOCUS, win->GetId() );
60 event.SetEventObject( win );
61
62 (void)win->GetEventHandler()->ProcessEvent( event );
63
64 return TRUE;
65}
865bb325 66}
f7204798 67
9f41d601
RR
68//-----------------------------------------------------------------------------
69// "focus" from m_window
70//-----------------------------------------------------------------------------
71
865bb325 72extern "C" {
9f41d601
RR
73static gint gtk_dialog_focus_callback( GtkWidget *widget, GtkDirectionType WXUNUSED(d), wxWindow *WXUNUSED(win) )
74{
75 if (g_isIdle)
76 wxapp_install_idle_handler();
77
33c0d0ed 78 /* This disables GTK's tab traversal */
9fa72bd2 79 g_signal_stop_emission_by_name (widget, "focus");
9f41d601
RR
80 return TRUE;
81}
865bb325 82}
9f41d601
RR
83
84//-----------------------------------------------------------------------------
85// "delete_event"
86//-----------------------------------------------------------------------------
87
865bb325 88extern "C" {
9f41d601
RR
89bool gtk_dialog_delete_callback( GtkWidget *WXUNUSED(widget), GdkEvent *WXUNUSED(event), wxPopupWindow *win )
90{
91 if (g_isIdle)
92 wxapp_install_idle_handler();
93
94 if (win->IsEnabled())
95 win->Close();
96
97 return TRUE;
98}
865bb325 99}
9f41d601 100
9f41d601
RR
101//-----------------------------------------------------------------------------
102// "realize" from m_widget
103//-----------------------------------------------------------------------------
104
105/* we cannot MWM hints and icons before the widget has been realized,
106 so we do this directly after realization */
107
865bb325 108extern "C" {
9f41d601
RR
109static gint
110gtk_dialog_realized_callback( GtkWidget * WXUNUSED(widget), wxPopupWindow *win )
111{
112 if (g_isIdle)
113 wxapp_install_idle_handler();
114
115 /* all this is for Motif Window Manager "hints" and is supposed to be
116 recognized by other WM as well. not tested. */
117 long decor = (long) GDK_DECOR_BORDER;
118 long func = (long) GDK_FUNC_MOVE ;
119
120 gdk_window_set_decorations( win->m_widget->window, (GdkWMDecoration)decor);
121 gdk_window_set_functions( win->m_widget->window, (GdkWMFunction)func);
122
43a52404 123 gtk_window_set_resizable(GTK_WINDOW(win->m_widget), FALSE);
9f41d601
RR
124
125 return FALSE;
126}
865bb325 127}
9f41d601
RR
128
129//-----------------------------------------------------------------------------
130// InsertChild for wxPopupWindow
131//-----------------------------------------------------------------------------
132
133/* Callback for wxFrame. This very strange beast has to be used because
134 * C++ has no virtual methods in a constructor. We have to emulate a
77ffb593 135 * virtual function here as wxWidgets requires different ways to insert
9f41d601
RR
136 * a child in container classes. */
137
138static void wxInsertChildInDialog( wxPopupWindow* parent, wxWindow* child )
139{
140 gtk_pizza_put( GTK_PIZZA(parent->m_wxwindow),
88d19775
MR
141 GTK_WIDGET(child->m_widget),
142 child->m_x,
143 child->m_y,
144 child->m_width,
145 child->m_height );
9f41d601
RR
146
147 if (parent->HasFlag(wxTAB_TRAVERSAL))
148 {
149 /* we now allow a window to get the focus as long as it
150 doesn't have any children. */
151 GTK_WIDGET_UNSET_FLAGS( parent->m_wxwindow, GTK_CAN_FOCUS );
152 }
153}
154
155//-----------------------------------------------------------------------------
156// wxPopupWindow
157//-----------------------------------------------------------------------------
158
8f0db49c
VS
159BEGIN_EVENT_TABLE(wxPopupWindow,wxPopupWindowBase)
160#ifdef __WXUNIVERSAL__
6522713c 161 EVT_SIZE(wxPopupWindow::OnSize)
8f0db49c 162#endif
9f41d601
RR
163END_EVENT_TABLE()
164
ad9fb033
RR
165wxPopupWindow::~wxPopupWindow()
166{
ad9fb033
RR
167}
168
9f41d601
RR
169bool wxPopupWindow::Create( wxWindow *parent, int style )
170{
670f9935 171 m_needParent = false;
9f41d601
RR
172
173 if (!PreCreation( parent, wxDefaultPosition, wxDefaultSize ) ||
2b5f62a0 174 !CreateBase( parent, -1, wxDefaultPosition, wxDefaultSize, style, wxDefaultValidator, wxT("popup") ))
9f41d601
RR
175 {
176 wxFAIL_MSG( wxT("wxPopupWindow creation failed") );
670f9935 177 return false;
9f41d601
RR
178 }
179
da19de36
RR
180 // Unlike windows, top level windows are created hidden by default.
181 m_isShown = false;
88d19775 182
9f41d601
RR
183 // All dialogs should really have this style
184 m_windowStyle |= wxTAB_TRAVERSAL;
185
186 m_insertCallback = (wxInsertChildFunction) wxInsertChildInDialog;
187
188 m_widget = gtk_window_new( GTK_WINDOW_POPUP );
189
190 if ((m_parent) && (GTK_IS_WINDOW(m_parent->m_widget)))
191 gtk_window_set_transient_for( GTK_WINDOW(m_widget), GTK_WINDOW(m_parent->m_widget) );
192
193 GTK_WIDGET_UNSET_FLAGS( m_widget, GTK_CAN_FOCUS );
194
9fa72bd2
MR
195 g_signal_connect (m_widget, "delete_event",
196 G_CALLBACK (gtk_dialog_delete_callback), this);
9f41d601
RR
197
198 m_wxwindow = gtk_pizza_new();
199 gtk_widget_show( m_wxwindow );
200 GTK_WIDGET_UNSET_FLAGS( m_wxwindow, GTK_CAN_FOCUS );
201
202 gtk_container_add( GTK_CONTAINER(m_widget), m_wxwindow );
203
204 if (m_parent) m_parent->AddChild( this );
205
206 PostCreation();
207
208 /* we cannot set MWM hints before the widget has
209 been realized, so we do this directly after realization */
9fa72bd2
MR
210 g_signal_connect (m_widget, "realize",
211 G_CALLBACK (gtk_dialog_realized_callback), this);
9f41d601 212
f7204798 213 // disable native tab traversal
9fa72bd2
MR
214 g_signal_connect (m_widget, "focus",
215 G_CALLBACK (gtk_dialog_focus_callback), this);
9f41d601 216
33c0d0ed
RR
217 m_time = gtk_get_current_event_time();
218
9fa72bd2
MR
219 g_signal_connect (m_widget, "button_press_event",
220 G_CALLBACK (gtk_popup_button_press), this);
88d19775 221
670f9935 222 return true;
9f41d601
RR
223}
224
225void wxPopupWindow::DoMoveWindow(int WXUNUSED(x), int WXUNUSED(y), int WXUNUSED(width), int WXUNUSED(height) )
226{
227 wxFAIL_MSG( wxT("DoMoveWindow called for wxPopupWindow") );
228}
229
230void wxPopupWindow::DoSetSize( int x, int y, int width, int height, int sizeFlags )
231{
232 wxASSERT_MSG( (m_widget != NULL), wxT("invalid dialog") );
233 wxASSERT_MSG( (m_wxwindow != NULL), wxT("invalid dialog") );
234
235 if (m_resizing) return; /* I don't like recursions */
670f9935 236 m_resizing = true;
9f41d601
RR
237
238 int old_x = m_x;
239 int old_y = m_y;
240
241 int old_width = m_width;
242 int old_height = m_height;
243
244 if ((sizeFlags & wxSIZE_ALLOW_MINUS_ONE) == 0)
245 {
246 if (x != -1) m_x = x;
247 if (y != -1) m_y = y;
248 if (width != -1) m_width = width;
249 if (height != -1) m_height = height;
250 }
251 else
252 {
253 m_x = x;
254 m_y = y;
255 m_width = width;
256 m_height = height;
257 }
258
259/*
260 if ((sizeFlags & wxSIZE_AUTO_WIDTH) == wxSIZE_AUTO_WIDTH)
261 {
262 if (width == -1) m_width = 80;
263 }
264
265 if ((sizeFlags & wxSIZE_AUTO_HEIGHT) == wxSIZE_AUTO_HEIGHT)
266 {
267 if (height == -1) m_height = 26;
268 }
269*/
270
e7dda1ff
VS
271 int minWidth = GetMinWidth(),
272 minHeight = GetMinHeight(),
273 maxWidth = GetMaxWidth(),
274 maxHeight = GetMaxHeight();
275
276 if ((minWidth != -1) && (m_width < minWidth)) m_width = minWidth;
277 if ((minHeight != -1) && (m_height < minHeight)) m_height = minHeight;
278 if ((maxWidth != -1) && (m_width > maxWidth)) m_width = maxWidth;
279 if ((maxHeight != -1) && (m_height > maxHeight)) m_height = maxHeight;
9f41d601
RR
280
281 if ((m_x != -1) || (m_y != -1))
282 {
283 if ((m_x != old_x) || (m_y != old_y))
284 {
285 /* we set the position here and when showing the dialog
286 for the first time in idle time */
cd6645a2
MR
287 // Where does that happen in idle time? I do not see it anywhere - MR
288 gtk_window_move( GTK_WINDOW(m_widget), m_x, m_y );
9f41d601
RR
289 }
290 }
291
292 if ((m_width != old_width) || (m_height != old_height))
293 {
370dc79c 294 gtk_widget_set_size_request( m_widget, m_width, m_height );
9f41d601
RR
295
296 /* actual resizing is deferred to GtkOnSize in idle time and
297 when showing the dialog */
670f9935 298 m_sizeSet = false;
9f41d601
RR
299
300 }
301
670f9935 302 m_resizing = false;
9f41d601
RR
303}
304
305void wxPopupWindow::GtkOnSize( int WXUNUSED(x), int WXUNUSED(y), int width, int height )
306{
307 // due to a bug in gtk, x,y are always 0
308 // m_x = x;
309 // m_y = y;
310
311 if ((m_height == height) && (m_width == width) && (m_sizeSet)) return;
312 if (!m_wxwindow) return;
313
314 m_width = width;
315 m_height = height;
316
ef00dc09 317 /* FIXME: is this a hack? */
7e027698
RR
318 /* Since for some reason GTK will revert to using maximum size ever set
319 for this window, we have to set geometry hints maxsize to match size
320 given. Also set the to that minsize since resizing isn't possible
321 anyway. */
9f41d601
RR
322
323 /* set size hints */
7e027698 324 gint flag = GDK_HINT_MAX_SIZE | GDK_HINT_MIN_SIZE; // GDK_HINT_POS;
9f41d601 325 GdkGeometry geom;
7e027698
RR
326 geom.min_width = m_width;
327 geom.min_height = m_height;
ef00dc09
RR
328 geom.max_width = m_width;
329 geom.max_height = m_height;
9f41d601
RR
330 gtk_window_set_geometry_hints( GTK_WINDOW(m_widget),
331 (GtkWidget*) NULL,
332 &geom,
333 (GdkWindowHints) flag );
334
ef00dc09 335
670f9935 336 m_sizeSet = true;
9f41d601
RR
337
338 wxSizeEvent event( wxSize(m_width,m_height), GetId() );
339 event.SetEventObject( this );
340 GetEventHandler()->ProcessEvent( event );
341}
342
343void wxPopupWindow::OnInternalIdle()
344{
345 if (!m_sizeSet && GTK_WIDGET_REALIZED(m_wxwindow))
346 GtkOnSize( m_x, m_y, m_width, m_height );
347
348 wxWindow::OnInternalIdle();
349}
350
351bool wxPopupWindow::Show( bool show )
352{
353 if (show && !m_sizeSet)
354 {
355 /* by calling GtkOnSize here, we don't have to call
356 either after showing the frame, which would entail
357 much ugly flicker nor from within the size_allocate
358 handler, because GTK 1.1.X forbids that. */
359
360 GtkOnSize( m_x, m_y, m_width, m_height );
361 }
88d19775 362
9f41d601 363 bool ret = wxWindow::Show( show );
88d19775 364
9f41d601
RR
365 return ret;
366}
367
f3ecfad1 368#endif // wxUSE_POPUPWIN