]> git.saurik.com Git - wxWidgets.git/blob - src/gtk/popupwin.cpp
added Collapse() and Expand()
[wxWidgets.git] / src / gtk / popupwin.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/gtk/popupwin.cpp
3 // Purpose:
4 // Author: Robert Roebling
5 // Id: $Id$
6 // Copyright: (c) 1998 Robert Roebling
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
9
10 // For compilers that support precompilation, includes "wx.h".
11 #include "wx/wxprec.h"
12
13 #if wxUSE_POPUPWIN
14
15 #include "wx/popupwin.h"
16
17 #ifndef WX_PRECOMP
18 #include "wx/app.h"
19 #include "wx/frame.h"
20 #include "wx/cursor.h"
21 #endif // WX_PRECOMP
22
23 #include <gtk/gtk.h>
24
25 #include "wx/gtk/win_gtk.h"
26
27 //-----------------------------------------------------------------------------
28 // "button_press"
29 //-----------------------------------------------------------------------------
30
31 extern "C" {
32 static gint gtk_popup_button_press (GtkWidget *widget, GdkEvent *gdk_event, wxPopupWindow* win )
33 {
34 GtkWidget *child = gtk_get_event_widget (gdk_event);
35
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. */
46 if (child != widget)
47 {
48 while (child)
49 {
50 if (child == widget)
51 return FALSE;
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 }
63 }
64
65 //-----------------------------------------------------------------------------
66 // "delete_event"
67 //-----------------------------------------------------------------------------
68
69 extern "C" {
70 bool gtk_dialog_delete_callback( GtkWidget *WXUNUSED(widget), GdkEvent *WXUNUSED(event), wxPopupWindow *win )
71 {
72 if (win->IsEnabled())
73 win->Close();
74
75 return TRUE;
76 }
77 }
78
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
86 extern "C" {
87 static gint
88 gtk_dialog_realized_callback( GtkWidget * WXUNUSED(widget), wxPopupWindow *win )
89 {
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
98 gtk_window_set_resizable(GTK_WINDOW(win->m_widget), FALSE);
99
100 return FALSE;
101 }
102 }
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
110 * virtual function here as wxWidgets requires different ways to insert
111 * a child in container classes. */
112
113 static void wxInsertChildInPopupWin(wxWindowGTK* parent, wxWindowGTK* child)
114 {
115 gtk_pizza_put( GTK_PIZZA(parent->m_wxwindow),
116 child->m_widget,
117 child->m_x,
118 child->m_y,
119 child->m_width,
120 child->m_height );
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
134 BEGIN_EVENT_TABLE(wxPopupWindow,wxPopupWindowBase)
135 #ifdef __WXUNIVERSAL__
136 EVT_SIZE(wxPopupWindow::OnSize)
137 #endif
138 END_EVENT_TABLE()
139
140 wxPopupWindow::~wxPopupWindow()
141 {
142 }
143
144 bool wxPopupWindow::Create( wxWindow *parent, int style )
145 {
146 m_sizeSet = false;
147
148 if (!PreCreation( parent, wxDefaultPosition, wxDefaultSize ) ||
149 !CreateBase( parent, -1, wxDefaultPosition, wxDefaultSize, style, wxDefaultValidator, wxT("popup") ))
150 {
151 wxFAIL_MSG( wxT("wxPopupWindow creation failed") );
152 return false;
153 }
154
155 // Unlike windows, top level windows are created hidden by default.
156 m_isShown = false;
157
158 // All dialogs should really have this style
159 m_windowStyle |= wxTAB_TRAVERSAL;
160
161 m_insertCallback = wxInsertChildInPopupWin;
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
170 g_signal_connect (m_widget, "delete_event",
171 G_CALLBACK (gtk_dialog_delete_callback), this);
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 */
185 g_signal_connect (m_widget, "realize",
186 G_CALLBACK (gtk_dialog_realized_callback), this);
187
188 m_time = gtk_get_current_event_time();
189
190 g_signal_connect (m_widget, "button_press_event",
191 G_CALLBACK (gtk_popup_button_press), this);
192
193 return true;
194 }
195
196 void 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
201 void 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 */
207 m_resizing = true;
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
242 ConstrainSize();
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 */
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 );
252 }
253 }
254
255 if ((m_width != old_width) || (m_height != old_height))
256 {
257 gtk_widget_set_size_request( m_widget, m_width, m_height );
258
259 /* actual resizing is deferred to GtkOnSize in idle time and
260 when showing the dialog */
261 m_sizeSet = false;
262
263 }
264
265 m_resizing = false;
266 }
267
268 void wxPopupWindow::GtkOnSize()
269 {
270 if (m_sizeSet) return;
271 if (!m_wxwindow) return;
272
273 /* FIXME: is this a hack? */
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. */
278
279 /* set size hints */
280 gint flag = GDK_HINT_MAX_SIZE | GDK_HINT_MIN_SIZE; // GDK_HINT_POS;
281 GdkGeometry geom;
282 geom.min_width = m_width;
283 geom.min_height = m_height;
284 geom.max_width = m_width;
285 geom.max_height = m_height;
286 gtk_window_set_geometry_hints( GTK_WINDOW(m_widget),
287 (GtkWidget*) NULL,
288 &geom,
289 (GdkWindowHints) flag );
290
291
292 m_sizeSet = true;
293
294 wxSizeEvent event( wxSize(m_width,m_height), GetId() );
295 event.SetEventObject( this );
296 GetEventHandler()->ProcessEvent( event );
297 }
298
299 void wxPopupWindow::OnInternalIdle()
300 {
301 if (!m_sizeSet && GTK_WIDGET_REALIZED(m_wxwindow))
302 GtkOnSize();
303
304 wxWindow::OnInternalIdle();
305 }
306
307 bool 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
316 GtkOnSize();
317 }
318
319 bool ret = wxWindow::Show( show );
320
321 return ret;
322 }
323
324 #endif // wxUSE_POPUPWIN