]> git.saurik.com Git - wxWidgets.git/blame - src/gtk1/popupwin.cpp
Disable wxUSE_ENH_METAFILE for wxGTK builds.
[wxWidgets.git] / src / gtk1 / popupwin.cpp
CommitLineData
9f41d601 1/////////////////////////////////////////////////////////////////////////////
670f9935 2// Name: src/gtk1/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
3cbab641 27#include "wx/gtk1/win_gtk.h"
9f41d601
RR
28
29//-----------------------------------------------------------------------------
30// idle system
31//-----------------------------------------------------------------------------
32
33extern void wxapp_install_idle_handler();
34extern bool g_isIdle;
35
f7204798
RR
36//-----------------------------------------------------------------------------
37// "button_press"
38//-----------------------------------------------------------------------------
39
865bb325 40extern "C" {
f7204798
RR
41static gint gtk_popup_button_press (GtkWidget *widget, GdkEvent *gdk_event, wxPopupWindow* win )
42{
43 GtkWidget *child = gtk_get_event_widget (gdk_event);
44
45 /* We don't ask for button press events on the grab widget, so
46 * if an event is reported directly to the grab widget, it must
47 * be on a window outside the application (and thus we remove
48 * the popup window). Otherwise, we check if the widget is a child
49 * of the grab widget, and only remove the popup window if it
50 * is not.
51 */
52 if (child != widget)
53 {
54 while (child)
88d19775
MR
55 {
56 if (child == widget)
57 return FALSE;
f7204798
RR
58 child = child->parent;
59 }
60 }
61
62 wxFocusEvent event( wxEVT_KILL_FOCUS, win->GetId() );
63 event.SetEventObject( win );
64
937013e0 65 (void)win->HandleWindowEvent( event );
f7204798
RR
66
67 return TRUE;
68}
865bb325 69}
f7204798 70
9f41d601
RR
71//-----------------------------------------------------------------------------
72// "focus" from m_window
73//-----------------------------------------------------------------------------
74
865bb325 75extern "C" {
9f41d601
RR
76static gint gtk_dialog_focus_callback( GtkWidget *widget, GtkDirectionType WXUNUSED(d), wxWindow *WXUNUSED(win) )
77{
78 if (g_isIdle)
79 wxapp_install_idle_handler();
80
81 // This disables GTK's tab traversal
82 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "focus" );
83 return TRUE;
84}
865bb325 85}
9f41d601
RR
86
87//-----------------------------------------------------------------------------
88// "delete_event"
89//-----------------------------------------------------------------------------
90
865bb325 91extern "C" {
9f41d601
RR
92bool gtk_dialog_delete_callback( GtkWidget *WXUNUSED(widget), GdkEvent *WXUNUSED(event), wxPopupWindow *win )
93{
94 if (g_isIdle)
95 wxapp_install_idle_handler();
96
97 if (win->IsEnabled())
98 win->Close();
99
100 return TRUE;
101}
865bb325 102}
9f41d601 103
9f41d601
RR
104//-----------------------------------------------------------------------------
105// "realize" from m_widget
106//-----------------------------------------------------------------------------
107
108/* we cannot MWM hints and icons before the widget has been realized,
109 so we do this directly after realization */
110
865bb325 111extern "C" {
9f41d601
RR
112static gint
113gtk_dialog_realized_callback( GtkWidget * WXUNUSED(widget), wxPopupWindow *win )
114{
115 if (g_isIdle)
116 wxapp_install_idle_handler();
117
118 /* all this is for Motif Window Manager "hints" and is supposed to be
119 recognized by other WM as well. not tested. */
120 long decor = (long) GDK_DECOR_BORDER;
121 long func = (long) GDK_FUNC_MOVE ;
122
123 gdk_window_set_decorations( win->m_widget->window, (GdkWMDecoration)decor);
124 gdk_window_set_functions( win->m_widget->window, (GdkWMFunction)func);
125
f7204798 126 gtk_window_set_policy(GTK_WINDOW(win->m_widget), 0, 0, 1);
9f41d601
RR
127
128 return FALSE;
129}
865bb325 130}
9f41d601
RR
131
132//-----------------------------------------------------------------------------
133// InsertChild for wxPopupWindow
134//-----------------------------------------------------------------------------
135
136/* Callback for wxFrame. This very strange beast has to be used because
137 * C++ has no virtual methods in a constructor. We have to emulate a
77ffb593 138 * virtual function here as wxWidgets requires different ways to insert
9f41d601
RR
139 * a child in container classes. */
140
141static void wxInsertChildInDialog( wxPopupWindow* parent, wxWindow* child )
142{
143 gtk_pizza_put( GTK_PIZZA(parent->m_wxwindow),
88d19775
MR
144 GTK_WIDGET(child->m_widget),
145 child->m_x,
146 child->m_y,
147 child->m_width,
148 child->m_height );
9f41d601
RR
149
150 if (parent->HasFlag(wxTAB_TRAVERSAL))
151 {
152 /* we now allow a window to get the focus as long as it
153 doesn't have any children. */
154 GTK_WIDGET_UNSET_FLAGS( parent->m_wxwindow, GTK_CAN_FOCUS );
155 }
156}
157
158//-----------------------------------------------------------------------------
159// wxPopupWindow
160//-----------------------------------------------------------------------------
161
8f0db49c
VS
162BEGIN_EVENT_TABLE(wxPopupWindow,wxPopupWindowBase)
163#ifdef __WXUNIVERSAL__
6522713c 164 EVT_SIZE(wxPopupWindow::OnSize)
8f0db49c 165#endif
9f41d601
RR
166END_EVENT_TABLE()
167
ad9fb033
RR
168wxPopupWindow::~wxPopupWindow()
169{
ad9fb033
RR
170}
171
9f41d601
RR
172bool wxPopupWindow::Create( wxWindow *parent, int style )
173{
670f9935 174 m_needParent = false;
9f41d601
RR
175
176 if (!PreCreation( parent, wxDefaultPosition, wxDefaultSize ) ||
2b5f62a0 177 !CreateBase( parent, -1, wxDefaultPosition, wxDefaultSize, style, wxDefaultValidator, wxT("popup") ))
9f41d601
RR
178 {
179 wxFAIL_MSG( wxT("wxPopupWindow creation failed") );
670f9935 180 return false;
9f41d601
RR
181 }
182
da19de36
RR
183 // Unlike windows, top level windows are created hidden by default.
184 m_isShown = false;
88d19775 185
9f41d601
RR
186 // All dialogs should really have this style
187 m_windowStyle |= wxTAB_TRAVERSAL;
188
189 m_insertCallback = (wxInsertChildFunction) wxInsertChildInDialog;
190
191 m_widget = gtk_window_new( GTK_WINDOW_POPUP );
192
193 if ((m_parent) && (GTK_IS_WINDOW(m_parent->m_widget)))
194 gtk_window_set_transient_for( GTK_WINDOW(m_widget), GTK_WINDOW(m_parent->m_widget) );
195
196 GTK_WIDGET_UNSET_FLAGS( m_widget, GTK_CAN_FOCUS );
197
198 gtk_signal_connect( GTK_OBJECT(m_widget), "delete_event",
199 GTK_SIGNAL_FUNC(gtk_dialog_delete_callback), (gpointer)this );
200
201 m_wxwindow = gtk_pizza_new();
202 gtk_widget_show( m_wxwindow );
203 GTK_WIDGET_UNSET_FLAGS( m_wxwindow, GTK_CAN_FOCUS );
204
205 gtk_container_add( GTK_CONTAINER(m_widget), m_wxwindow );
206
207 if (m_parent) m_parent->AddChild( this );
208
209 PostCreation();
210
211 /* we cannot set MWM hints before the widget has
212 been realized, so we do this directly after realization */
213 gtk_signal_connect( GTK_OBJECT(m_widget), "realize",
214 GTK_SIGNAL_FUNC(gtk_dialog_realized_callback), (gpointer) this );
215
f7204798 216 // disable native tab traversal
9f41d601
RR
217 gtk_signal_connect( GTK_OBJECT(m_widget), "focus",
218 GTK_SIGNAL_FUNC(gtk_dialog_focus_callback), (gpointer)this );
219
fbe99a7e
RR
220 gtk_signal_connect (GTK_OBJECT(m_widget), "button_press_event",
221 GTK_SIGNAL_FUNC(gtk_popup_button_press), (gpointer)this );
88d19775 222
c8326d64 223 return true;
9f41d601
RR
224}
225
226void wxPopupWindow::DoMoveWindow(int WXUNUSED(x), int WXUNUSED(y), int WXUNUSED(width), int WXUNUSED(height) )
227{
228 wxFAIL_MSG( wxT("DoMoveWindow called for wxPopupWindow") );
229}
230
231void wxPopupWindow::DoSetSize( int x, int y, int width, int height, int sizeFlags )
232{
233 wxASSERT_MSG( (m_widget != NULL), wxT("invalid dialog") );
234 wxASSERT_MSG( (m_wxwindow != NULL), wxT("invalid dialog") );
235
236 if (m_resizing) return; /* I don't like recursions */
670f9935 237 m_resizing = true;
9f41d601
RR
238
239 int old_x = m_x;
240 int old_y = m_y;
241
242 int old_width = m_width;
243 int old_height = m_height;
244
245 if ((sizeFlags & wxSIZE_ALLOW_MINUS_ONE) == 0)
246 {
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;
251 }
252 else
253 {
254 m_x = x;
255 m_y = y;
256 m_width = width;
257 m_height = height;
258 }
259
260/*
261 if ((sizeFlags & wxSIZE_AUTO_WIDTH) == wxSIZE_AUTO_WIDTH)
262 {
263 if (width == -1) m_width = 80;
264 }
265
266 if ((sizeFlags & wxSIZE_AUTO_HEIGHT) == wxSIZE_AUTO_HEIGHT)
267 {
268 if (height == -1) m_height = 26;
269 }
270*/
271
e7dda1ff
VS
272 int minWidth = GetMinWidth(),
273 minHeight = GetMinHeight(),
274 maxWidth = GetMaxWidth(),
275 maxHeight = GetMaxHeight();
276
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;
9f41d601
RR
281
282 if ((m_x != -1) || (m_y != -1))
283 {
284 if ((m_x != old_x) || (m_y != old_y))
285 {
286 /* we set the position here and when showing the dialog
287 for the first time in idle time */
288 gtk_widget_set_uposition( m_widget, m_x, m_y );
289 }
290 }
291
292 if ((m_width != old_width) || (m_height != old_height))
293 {
294 gtk_widget_set_usize( m_widget, m_width, m_height );
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 330 gtk_window_set_geometry_hints( GTK_WINDOW(m_widget),
d3b9f782 331 NULL,
9f41d601
RR
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 );
937013e0 340 HandleWindowEvent( event );
9f41d601
RR
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