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