]> git.saurik.com Git - wxWidgets.git/blob - src/gtk/window.cpp
86fc0bed68fc56882d7899bb3c41e18be94b975d
[wxWidgets.git] / src / gtk / window.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: window.cpp
3 // Purpose:
4 // Author: Robert Roebling
5 // Id: $Id$
6 // Copyright: (c) 1998 Robert Roebling, Julian Smart
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
9
10
11 #ifdef __GNUG__
12 #pragma implementation "window.h"
13 #endif
14
15 #include "wx/defs.h"
16 #include "wx/window.h"
17 #include "wx/dc.h"
18 #include "wx/frame.h"
19 #include "wx/app.h"
20 #include "wx/layout.h"
21 #include "wx/utils.h"
22 #include "wx/dialog.h"
23 #include "wx/msgdlg.h"
24
25 #if wxUSE_DRAG_AND_DROP
26 #include "wx/dnd.h"
27 #endif
28
29 #if wxUSE_TOOLTIPS
30 #include "wx/tooltip.h"
31 #endif
32
33 #include "wx/menu.h"
34 #include "wx/statusbr.h"
35 #include "wx/intl.h"
36 #include "wx/settings.h"
37 #include "wx/log.h"
38
39 #include <math.h>
40
41 #include "gdk/gdk.h"
42 #include "gtk/gtk.h"
43 #include "gdk/gdkprivate.h"
44 #include "gdk/gdkkeysyms.h"
45 #include "wx/gtk/win_gtk.h"
46
47 //-----------------------------------------------------------------------------
48 // documentation on internals
49 //-----------------------------------------------------------------------------
50
51 /*
52 I have been asked several times about writing some documentation about
53 the GTK port of wxWindows, especially its internal structures. Obviously,
54 you cannot understand wxGTK without knowing a little about the GTK, but
55 some more information about what the wxWindow, which is the base class
56 for all other window classes, does seems required as well.
57
58 What does wxWindow do? It contains the common interface for the following
59 jobs of its descendants:
60
61 1) Define the rudimentary behaviour common to all window classes, such as
62 resizing, intercepting user input (so as to make it possible to use these
63 events for special purposes in a derived class), window names etc.
64
65 2) Provide the possibility to contain and manage children, if the derived
66 class is allowed to contain children, which holds true for those window
67 classes which do not display a native GTK widget. To name them, these
68 classes are wxPanel, wxScrolledWindow, wxDialog, wxFrame. The MDI frame-
69 work classes are a special case and are handled a bit differently from
70 the rest. The same holds true for the wxNotebook class.
71
72 3) Provide the possibility to draw into a client area of a window. This,
73 too, only holds true for classes that do not display a native GTK widget
74 as above.
75
76 4) Provide the entire mechanism for scrolling widgets. This actual inter-
77 face for this is usually in wxScrolledWindow, but the GTK implementation
78 is in this class.
79
80 5) A multitude of helper or extra methods for special purposes, such as
81 Drag'n'Drop, managing validators etc.
82
83 Normally one might expect, that one wxWindows window would always correspond
84 to one GTK widget. Under GTK, there is no such allround widget that has all
85 the functionality. Moreover, the GTK defines a client area as a different
86 widget from the actual widget you are handling. Last but not least some
87 special classes (e.g. wxFrame) handle different categories of widgets and
88 still have the possibility to draw something in the client area.
89 It was therefore required to write a special purpose GTK widget, that would
90 represent a client area in the sense of wxWindows capable to do the jobs
91 2), 3) and 4). I have written this class and it resides in win_gtk.c of
92 this directory.
93
94 All windows must have a widget, with which they interact with other under-
95 lying GTK widgets. It is this widget, e.g. that has to be resized etc and
96 thw wxWindow class has a member variable called m_widget which holds a
97 pointer to this widget. When the window class represents a GTK native widget,
98 this is (in most cases) the only GTK widget the class manages. E.g. the
99 wxStatitText class handles only a GtkLabel widget a pointer to which you
100 can find in m_widget (defined in wxWindow)
101
102 When the class has a client area for drawing into and for containing children
103 it has to handle the client area widget (of the type GtkMyFixed, defined in
104 win_gtk.c), but there could be any number of widgets, handled by a class
105 The common rule for all windows is only, that the widget that interacts with
106 the rest of GTK must be referenced in m_widget and all other widgets must be
107 children of this widget on the GTK level. The top-most widget, which also
108 represents the client area, must be in the m_wxwindow field and must be of
109 the type GtkMyFixed.
110
111 As I said, the window classes that display a GTK native widget only have
112 one widget, so in the case of e.g. the wxButton class m_widget holds a
113 pointer to a GtkButton widget. But windows with client areas (for drawing
114 and children) have a m_widget field that is a pointer to a GtkScrolled-
115 Window and a m_wxwindow field that is pointer to a GtkMyFixed and this
116 one is (in the GTK sense) a child of the GtkScrolledWindow.
117
118 If the m_wxwindow field is set, then all input to this widget is inter-
119 cepted and sent to the wxWindows class. If not, all input to the widget
120 that gets pointed to by m_widget gets intercepted and sent to the class.
121
122 */
123
124 //-----------------------------------------------------------------------------
125 // data
126 //-----------------------------------------------------------------------------
127
128 extern wxList wxPendingDelete;
129 extern bool g_blockEventsOnDrag;
130 extern bool g_blockEventsOnScroll;
131 static bool g_capturing = FALSE;
132 static wxWindow *g_focusWindow = (wxWindow*) NULL;
133
134 /* hack: we need something to pass to gtk_menu_popup, so we store the time of
135 the last click here */
136 static guint32 gs_timeLastClick = 0;
137
138 #if (GTK_MINOR_VERSION > 0)
139
140 //-----------------------------------------------------------------------------
141 // local code (see below)
142 //-----------------------------------------------------------------------------
143
144 static void draw_frame( GtkWidget *widget, wxWindow *win )
145 {
146 if (!win->HasVMT()) return;
147
148 int dw = 0;
149 int dh = 0;
150
151 if (win->m_hasScrolling)
152 {
153 GtkScrolledWindow *scroll_window = GTK_SCROLLED_WINDOW(widget);
154 GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT(widget)->klass );
155
156 /*
157 GtkWidget *hscrollbar = scroll_window->hscrollbar;
158 GtkWidget *vscrollbar = scroll_window->vscrollbar;
159
160 we use this instead: range.slider_width = 11 + 2*2pts edge
161 */
162
163 if (scroll_window->vscrollbar_visible)
164 {
165 dw += 15; /* dw += vscrollbar->allocation.width; */
166 dw += scroll_class->scrollbar_spacing;
167 }
168
169 if (scroll_window->hscrollbar_visible)
170 {
171 dh += 15; /* dh += hscrollbar->allocation.height; */
172 dw += scroll_class->scrollbar_spacing;
173 }
174 }
175
176 int dx = 0;
177 int dy = 0;
178 if (GTK_WIDGET_NO_WINDOW (widget))
179 {
180 dx += widget->allocation.x;
181 dy += widget->allocation.y;
182 }
183
184 if (win->m_windowStyle & wxRAISED_BORDER)
185 {
186 gtk_draw_shadow( widget->style,
187 widget->window,
188 GTK_STATE_NORMAL,
189 GTK_SHADOW_OUT,
190 dx, dy,
191 win->m_width-dw, win->m_height-dh );
192 return;
193 }
194
195 if (win->m_windowStyle & wxSUNKEN_BORDER)
196 {
197 gtk_draw_shadow( widget->style,
198 widget->window,
199 GTK_STATE_NORMAL,
200 GTK_SHADOW_IN,
201 dx, dy,
202 win->m_width-dw, win->m_height-dh );
203 return;
204 }
205 }
206
207 //-----------------------------------------------------------------------------
208 // "expose_event" of m_widget
209 //-----------------------------------------------------------------------------
210
211 static void gtk_window_own_expose_callback( GtkWidget *widget, GdkEventExpose *gdk_event, wxWindow *win )
212 {
213 if (gdk_event->count > 0) return;
214 draw_frame( widget, win );
215 }
216
217 //-----------------------------------------------------------------------------
218 // "draw" of m_wxwindow
219 //-----------------------------------------------------------------------------
220
221 static void gtk_window_own_draw_callback( GtkWidget *widget, GdkRectangle *WXUNUSED(rect), wxWindow *win )
222 {
223 draw_frame( widget, win );
224 }
225
226 #endif
227
228 //-----------------------------------------------------------------------------
229 // "expose_event" of m_wxwindow
230 //-----------------------------------------------------------------------------
231
232 static void gtk_window_expose_callback( GtkWidget *WXUNUSED(widget), GdkEventExpose *gdk_event, wxWindow *win )
233 {
234 if (!win->HasVMT()) return;
235
236 win->m_updateRegion.Union( gdk_event->area.x,
237 gdk_event->area.y,
238 gdk_event->area.width,
239 gdk_event->area.height );
240
241 if (gdk_event->count > 0) return;
242
243 /*
244 printf( "OnExpose from " );
245 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
246 printf( win->GetClassInfo()->GetClassName() );
247 printf( ".\n" );
248 */
249
250 wxPaintEvent event( win->GetId() );
251 event.SetEventObject( win );
252 win->GetEventHandler()->ProcessEvent( event );
253
254 win->m_updateRegion.Clear();
255 }
256
257 //-----------------------------------------------------------------------------
258 // "draw" of m_wxwindow
259 //-----------------------------------------------------------------------------
260
261 static void gtk_window_draw_callback( GtkWidget *WXUNUSED(widget), GdkRectangle *rect, wxWindow *win )
262 {
263 if (!win->HasVMT()) return;
264
265 win->m_updateRegion.Union( rect->x, rect->y, rect->width, rect->height );
266
267 wxPaintEvent event( win->GetId() );
268 event.SetEventObject( win );
269 win->GetEventHandler()->ProcessEvent( event );
270
271 win->m_updateRegion.Clear();
272 }
273
274 //-----------------------------------------------------------------------------
275 // "key_press_event" from any window
276 //-----------------------------------------------------------------------------
277
278 static gint gtk_window_key_press_callback( GtkWidget *widget, GdkEventKey *gdk_event, wxWindow *win )
279 {
280 if (!win->HasVMT()) return FALSE;
281 if (g_blockEventsOnDrag) return FALSE;
282
283 /*
284 printf( "OnKeyPress from " );
285 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
286 printf( win->GetClassInfo()->GetClassName() );
287 printf( ".\n" );
288 */
289
290 long key_code = 0;
291 switch (gdk_event->keyval)
292 {
293 case GDK_BackSpace: key_code = WXK_BACK; break;
294 case GDK_ISO_Left_Tab:
295 case GDK_KP_Tab:
296 case GDK_Tab: key_code = WXK_TAB; break;
297 case GDK_Linefeed: key_code = WXK_RETURN; break;
298 case GDK_Clear: key_code = WXK_CLEAR; break;
299 case GDK_Return: key_code = WXK_RETURN; break;
300 case GDK_Pause: key_code = WXK_PAUSE; break;
301 case GDK_Scroll_Lock: key_code = WXK_SCROLL; break;
302 case GDK_Escape: key_code = WXK_ESCAPE; break;
303 case GDK_Delete: key_code = WXK_DELETE; break;
304 case GDK_Home: key_code = WXK_HOME; break;
305 case GDK_Left: key_code = WXK_LEFT; break;
306 case GDK_Up: key_code = WXK_UP; break;
307 case GDK_Right: key_code = WXK_RIGHT; break;
308 case GDK_Down: key_code = WXK_DOWN; break;
309 case GDK_Prior: key_code = WXK_PRIOR; break;
310 // case GDK_Page_Up: key_code = WXK_PAGEUP; break;
311 case GDK_Next: key_code = WXK_NEXT; break;
312 // case GDK_Page_Down: key_code = WXK_PAGEDOWN; break;
313 case GDK_End: key_code = WXK_END; break;
314 case GDK_Begin: key_code = WXK_HOME; break;
315 case GDK_Select: key_code = WXK_SELECT; break;
316 case GDK_Print: key_code = WXK_PRINT; break;
317 case GDK_Execute: key_code = WXK_EXECUTE; break;
318 case GDK_Insert: key_code = WXK_INSERT; break;
319 case GDK_Num_Lock: key_code = WXK_NUMLOCK; break;
320 case GDK_KP_Enter: key_code = WXK_RETURN; break;
321 case GDK_KP_Home: key_code = WXK_HOME; break;
322 case GDK_KP_Left: key_code = WXK_LEFT; break;
323 case GDK_KP_Up: key_code = WXK_UP; break;
324 case GDK_KP_Right: key_code = WXK_RIGHT; break;
325 case GDK_KP_Down: key_code = WXK_DOWN; break;
326 case GDK_KP_Prior: key_code = WXK_PRIOR; break;
327 // case GDK_KP_Page_Up: key_code = WXK_PAGEUP; break;
328 case GDK_KP_Next: key_code = WXK_NEXT; break;
329 // case GDK_KP_Page_Down: key_code = WXK_PAGEDOWN; break;
330 case GDK_KP_End: key_code = WXK_END; break;
331 case GDK_KP_Begin: key_code = WXK_HOME; break;
332 case GDK_KP_Insert: key_code = WXK_INSERT; break;
333 case GDK_KP_Delete: key_code = WXK_DELETE; break;
334 case GDK_KP_Multiply: key_code = WXK_MULTIPLY; break;
335 case GDK_KP_Add: key_code = WXK_ADD; break;
336 case GDK_KP_Separator: key_code = WXK_SEPARATOR; break;
337 case GDK_KP_Subtract: key_code = WXK_SUBTRACT; break;
338 case GDK_KP_Decimal: key_code = WXK_DECIMAL; break;
339 case GDK_KP_Divide: key_code = WXK_DIVIDE; break;
340 case GDK_KP_0: key_code = WXK_NUMPAD0; break;
341 case GDK_KP_1: key_code = WXK_NUMPAD1; break;
342 case GDK_KP_2: key_code = WXK_NUMPAD2; break;
343 case GDK_KP_3: key_code = WXK_NUMPAD3; break;
344 case GDK_KP_4: key_code = WXK_NUMPAD4; break;
345 case GDK_KP_5: key_code = WXK_NUMPAD5; break;
346 case GDK_KP_6: key_code = WXK_NUMPAD6; break;
347 case GDK_KP_7: key_code = WXK_NUMPAD7; break;
348 case GDK_KP_8: key_code = WXK_NUMPAD7; break;
349 case GDK_KP_9: key_code = WXK_NUMPAD9; break;
350 case GDK_F1: key_code = WXK_F1; break;
351 case GDK_F2: key_code = WXK_F2; break;
352 case GDK_F3: key_code = WXK_F3; break;
353 case GDK_F4: key_code = WXK_F4; break;
354 case GDK_F5: key_code = WXK_F5; break;
355 case GDK_F6: key_code = WXK_F6; break;
356 case GDK_F7: key_code = WXK_F7; break;
357 case GDK_F8: key_code = WXK_F8; break;
358 case GDK_F9: key_code = WXK_F9; break;
359 case GDK_F10: key_code = WXK_F10; break;
360 case GDK_F11: key_code = WXK_F11; break;
361 case GDK_F12: key_code = WXK_F12; break;
362 default:
363 {
364 if ((gdk_event->keyval >= 0x20) && (gdk_event->keyval <= 0xFF))
365 key_code = gdk_event->keyval;
366 }
367 }
368
369 if (!key_code) return FALSE;
370
371 wxKeyEvent event( wxEVT_KEY_DOWN );
372 event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK);
373 event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK);
374 event.m_altDown = (gdk_event->state & GDK_MOD1_MASK);
375 event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK);
376 event.m_keyCode = key_code;
377 event.m_x = 0;
378 event.m_y = 0;
379 event.SetEventObject( win );
380
381 bool ret = win->GetEventHandler()->ProcessEvent( event );
382
383 if (!ret)
384 {
385 wxWindow *ancestor = win;
386 while (ancestor)
387 {
388 int command = ancestor->GetAcceleratorTable()->GetCommand( event );
389 if (command != -1)
390 {
391 wxCommandEvent command_event( wxEVT_COMMAND_MENU_SELECTED, command );
392 ret = ancestor->GetEventHandler()->ProcessEvent( command_event );
393 break;
394 }
395 ancestor = ancestor->GetParent();
396 }
397 }
398
399 // win is a control: tab can be propagated up
400 if ( (!ret) &&
401 ((gdk_event->keyval == GDK_Tab) || (gdk_event->keyval == GDK_ISO_Left_Tab)) &&
402 ((win->m_windowStyle & wxTE_PROCESS_TAB) == 0))
403 {
404 wxNavigationKeyEvent new_event;
405 /* GDK reports GDK_ISO_Left_Tab for SHIFT-TAB */
406 new_event.SetDirection( (gdk_event->keyval == GDK_Tab) );
407 /* CTRL-TAB changes the (parent) window, i.e. switch notebook page */
408 new_event.SetWindowChange( (gdk_event->state & GDK_CONTROL_MASK) );
409 new_event.SetCurrentFocus( win );
410 ret = win->GetEventHandler()->ProcessEvent( new_event );
411 }
412
413 if ( (!ret) &&
414 (gdk_event->keyval == GDK_Escape) )
415 {
416 wxCommandEvent new_event(wxEVT_COMMAND_BUTTON_CLICKED,wxID_CANCEL);
417 new_event.SetEventObject( win );
418 ret = win->GetEventHandler()->ProcessEvent( new_event );
419 }
420
421 /*
422 Damn, I forgot why this didn't work, but it didn't work.
423
424 // win is a panel: up can be propagated to the panel
425 if ((!ret) && (win->m_wxwindow) && (win->m_parent) && (win->m_parent->AcceptsFocus()) &&
426 (gdk_event->keyval == GDK_Up))
427 {
428 win->m_parent->SetFocus();
429 ret = TRUE;
430 }
431
432 // win is a panel: left/right can be propagated to the panel
433 if ((!ret) && (win->m_wxwindow) &&
434 ((gdk_event->keyval == GDK_Right) || (gdk_event->keyval == GDK_Left) ||
435 (gdk_event->keyval == GDK_Up) || (gdk_event->keyval == GDK_Down)))
436 {
437 wxNavigationKeyEvent new_event;
438 new_event.SetDirection( (gdk_event->keyval == GDK_Right) || (gdk_event->keyval == GDK_Down) );
439 new_event.SetCurrentFocus( win );
440 ret = win->GetEventHandler()->ProcessEvent( new_event );
441 }
442 */
443
444 if (ret)
445 {
446 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "key_press_event" );
447 return TRUE;
448 }
449
450 return FALSE;
451 }
452
453 //-----------------------------------------------------------------------------
454 // "key_release_event" from any window
455 //-----------------------------------------------------------------------------
456
457 static gint gtk_window_key_release_callback( GtkWidget *widget, GdkEventKey *gdk_event, wxWindow *win )
458 {
459 if (!win->HasVMT()) return FALSE;
460 if (g_blockEventsOnDrag) return FALSE;
461
462 /*
463 printf( "OnKeyRelease from " );
464 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
465 printf( win->GetClassInfo()->GetClassName() );
466 printf( ".\n" );
467 */
468
469 long key_code = 0;
470 switch (gdk_event->keyval)
471 {
472 case GDK_BackSpace: key_code = WXK_BACK; break;
473 case GDK_ISO_Left_Tab:
474 case GDK_KP_Tab:
475 case GDK_Tab: key_code = WXK_TAB; break;
476 case GDK_Linefeed: key_code = WXK_RETURN; break;
477 case GDK_Clear: key_code = WXK_CLEAR; break;
478 case GDK_Return: key_code = WXK_RETURN; break;
479 case GDK_Pause: key_code = WXK_PAUSE; break;
480 case GDK_Scroll_Lock: key_code = WXK_SCROLL; break;
481 case GDK_Escape: key_code = WXK_ESCAPE; break;
482 case GDK_Delete: key_code = WXK_DELETE; break;
483 case GDK_Home: key_code = WXK_HOME; break;
484 case GDK_Left: key_code = WXK_LEFT; break;
485 case GDK_Up: key_code = WXK_UP; break;
486 case GDK_Right: key_code = WXK_RIGHT; break;
487 case GDK_Down: key_code = WXK_DOWN; break;
488 case GDK_Prior: key_code = WXK_PRIOR; break;
489 // case GDK_Page_Up: key_code = WXK_PAGEUP; break;
490 case GDK_Next: key_code = WXK_NEXT; break;
491 // case GDK_Page_Down: key_code = WXK_PAGEDOWN; break;
492 case GDK_End: key_code = WXK_END; break;
493 case GDK_Begin: key_code = WXK_HOME; break;
494 case GDK_Select: key_code = WXK_SELECT; break;
495 case GDK_Print: key_code = WXK_PRINT; break;
496 case GDK_Execute: key_code = WXK_EXECUTE; break;
497 case GDK_Insert: key_code = WXK_INSERT; break;
498 case GDK_Num_Lock: key_code = WXK_NUMLOCK; break;
499 case GDK_KP_Enter: key_code = WXK_RETURN; break;
500 case GDK_KP_Home: key_code = WXK_HOME; break;
501 case GDK_KP_Left: key_code = WXK_LEFT; break;
502 case GDK_KP_Up: key_code = WXK_UP; break;
503 case GDK_KP_Right: key_code = WXK_RIGHT; break;
504 case GDK_KP_Down: key_code = WXK_DOWN; break;
505 case GDK_KP_Prior: key_code = WXK_PRIOR; break;
506 // case GDK_KP_Page_Up: key_code = WXK_PAGEUP; break;
507 case GDK_KP_Next: key_code = WXK_NEXT; break;
508 // case GDK_KP_Page_Down: key_code = WXK_PAGEDOWN; break;
509 case GDK_KP_End: key_code = WXK_END; break;
510 case GDK_KP_Begin: key_code = WXK_HOME; break;
511 case GDK_KP_Insert: key_code = WXK_INSERT; break;
512 case GDK_KP_Delete: key_code = WXK_DELETE; break;
513 case GDK_KP_Multiply: key_code = WXK_MULTIPLY; break;
514 case GDK_KP_Add: key_code = WXK_ADD; break;
515 case GDK_KP_Separator: key_code = WXK_SEPARATOR; break;
516 case GDK_KP_Subtract: key_code = WXK_SUBTRACT; break;
517 case GDK_KP_Decimal: key_code = WXK_DECIMAL; break;
518 case GDK_KP_Divide: key_code = WXK_DIVIDE; break;
519 case GDK_KP_0: key_code = WXK_NUMPAD0; break;
520 case GDK_KP_1: key_code = WXK_NUMPAD1; break;
521 case GDK_KP_2: key_code = WXK_NUMPAD2; break;
522 case GDK_KP_3: key_code = WXK_NUMPAD3; break;
523 case GDK_KP_4: key_code = WXK_NUMPAD4; break;
524 case GDK_KP_5: key_code = WXK_NUMPAD5; break;
525 case GDK_KP_6: key_code = WXK_NUMPAD6; break;
526 case GDK_KP_7: key_code = WXK_NUMPAD7; break;
527 case GDK_KP_8: key_code = WXK_NUMPAD7; break;
528 case GDK_KP_9: key_code = WXK_NUMPAD9; break;
529 case GDK_F1: key_code = WXK_F1; break;
530 case GDK_F2: key_code = WXK_F2; break;
531 case GDK_F3: key_code = WXK_F3; break;
532 case GDK_F4: key_code = WXK_F4; break;
533 case GDK_F5: key_code = WXK_F5; break;
534 case GDK_F6: key_code = WXK_F6; break;
535 case GDK_F7: key_code = WXK_F7; break;
536 case GDK_F8: key_code = WXK_F8; break;
537 case GDK_F9: key_code = WXK_F9; break;
538 case GDK_F10: key_code = WXK_F10; break;
539 case GDK_F11: key_code = WXK_F11; break;
540 case GDK_F12: key_code = WXK_F12; break;
541 default:
542 {
543 if ((gdk_event->keyval >= 0x20) && (gdk_event->keyval <= 0xFF))
544 key_code = gdk_event->keyval;
545 }
546 }
547
548 if (!key_code) return FALSE;
549
550 wxKeyEvent event( wxEVT_KEY_UP );
551 event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK);
552 event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK);
553 event.m_altDown = (gdk_event->state & GDK_MOD1_MASK);
554 event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK);
555 event.m_keyCode = key_code;
556 event.m_x = 0;
557 event.m_y = 0;
558 event.SetEventObject( win );
559
560 if (win->GetEventHandler()->ProcessEvent( event ))
561 {
562 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "key_release_event" );
563 return TRUE;
564 }
565
566 return FALSE;
567 }
568
569 //-----------------------------------------------------------------------------
570 // "button_press_event"
571 //-----------------------------------------------------------------------------
572
573 static gint gtk_window_button_press_callback( GtkWidget *widget, GdkEventButton *gdk_event, wxWindow *win )
574 {
575 if (!win->HasVMT()) return FALSE;
576 if (g_blockEventsOnDrag) return TRUE;
577 if (g_blockEventsOnScroll) return TRUE;
578
579 if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
580
581 if (win->m_wxwindow)
582 {
583 if (GTK_WIDGET_CAN_FOCUS(win->m_wxwindow) && !GTK_WIDGET_HAS_FOCUS (win->m_wxwindow) )
584 {
585 gtk_widget_grab_focus (win->m_wxwindow);
586
587 /*
588 printf( "GrabFocus from " );
589 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
590 printf( win->GetClassInfo()->GetClassName() );
591 printf( ".\n" );
592 */
593
594 }
595 }
596
597 /*
598 printf( "OnButtonPress from " );
599 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
600 printf( win->GetClassInfo()->GetClassName() );
601 printf( ".\n" );
602 */
603
604 wxEventType event_type = wxEVT_LEFT_DOWN;
605
606 if (gdk_event->button == 1)
607 {
608 switch (gdk_event->type)
609 {
610 case GDK_BUTTON_PRESS: event_type = wxEVT_LEFT_DOWN; break;
611 case GDK_2BUTTON_PRESS: event_type = wxEVT_LEFT_DCLICK; break;
612 default: break;
613 }
614 }
615 else if (gdk_event->button == 2)
616 {
617 switch (gdk_event->type)
618 {
619 case GDK_BUTTON_PRESS: event_type = wxEVT_MIDDLE_DOWN; break;
620 case GDK_2BUTTON_PRESS: event_type = wxEVT_MIDDLE_DCLICK; break;
621 default: break;
622 }
623 }
624 else if (gdk_event->button == 3)
625 {
626 switch (gdk_event->type)
627 {
628 case GDK_BUTTON_PRESS: event_type = wxEVT_RIGHT_DOWN; break;
629 case GDK_2BUTTON_PRESS: event_type = wxEVT_RIGHT_DCLICK; break;
630 default: break;
631 }
632 }
633
634 wxMouseEvent event( event_type );
635 event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK);
636 event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK);
637 event.m_altDown = (gdk_event->state & GDK_MOD1_MASK);
638 event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK);
639 event.m_leftDown = (gdk_event->state & GDK_BUTTON1_MASK);
640 event.m_middleDown = (gdk_event->state & GDK_BUTTON2_MASK);
641 event.m_rightDown = (gdk_event->state & GDK_BUTTON3_MASK);
642
643 event.m_x = (long)gdk_event->x;
644 event.m_y = (long)gdk_event->y;
645
646 // Some control don't have their own X window and thus cannot get
647 // any events.
648
649 if (!g_capturing)
650 {
651 wxNode *node = win->GetChildren().First();
652 while (node)
653 {
654 wxWindow *child = (wxWindow*)node->Data();
655
656 if (child->m_isStaticBox)
657 {
658 // wxStaticBox is transparent in the box itself
659 int x = event.m_x;
660 int y = event.m_y;
661 int xx1 = child->m_x;
662 int yy1 = child->m_y;
663 int xx2 = child->m_x + child->m_width;
664 int yy2 = child->m_x + child->m_height;
665
666 // left
667 if (((x >= xx1) && (x <= xx1+10) && (y >= yy1) && (y <= yy2)) ||
668 // right
669 ((x >= xx2-10) && (x <= xx2) && (y >= yy1) && (y <= yy2)) ||
670 // top
671 ((x >= xx1) && (x <= xx2) && (y >= yy1) && (y <= yy1+10)) ||
672 // bottom
673 ((x >= xx1) && (x <= xx2) && (y >= yy2-1) && (y <= yy2)))
674 {
675 win = child;
676 event.m_x -= child->m_x;
677 event.m_y -= child->m_y;
678 break;
679 }
680
681 }
682 else
683 {
684 if ((child->m_wxwindow == (GtkWidget*) NULL) &&
685 (child->m_x <= event.m_x) &&
686 (child->m_y <= event.m_y) &&
687 (child->m_x+child->m_width >= event.m_x) &&
688 (child->m_y+child->m_height >= event.m_y))
689 {
690 win = child;
691 event.m_x -= child->m_x;
692 event.m_y -= child->m_y;
693 break;
694 }
695 }
696 node = node->Next();
697 }
698 }
699
700 event.SetEventObject( win );
701
702 gs_timeLastClick = gdk_event->time;
703
704 if (win->GetEventHandler()->ProcessEvent( event ))
705 {
706 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "button_press_event" );
707 return TRUE;
708 }
709
710 return FALSE;
711 }
712
713 //-----------------------------------------------------------------------------
714 // "button_release_event"
715 //-----------------------------------------------------------------------------
716
717 static gint gtk_window_button_release_callback( GtkWidget *widget, GdkEventButton *gdk_event, wxWindow *win )
718 {
719 if (!win->HasVMT()) return FALSE;
720 if (g_blockEventsOnDrag) return FALSE;
721 if (g_blockEventsOnScroll) return FALSE;
722
723 if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
724
725 /*
726 printf( "OnButtonRelease from " );
727 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
728 printf( win->GetClassInfo()->GetClassName() );
729 printf( ".\n" );
730 */
731
732 wxEventType event_type = wxEVT_NULL;
733
734 switch (gdk_event->button)
735 {
736 case 1: event_type = wxEVT_LEFT_UP; break;
737 case 2: event_type = wxEVT_MIDDLE_UP; break;
738 case 3: event_type = wxEVT_RIGHT_UP; break;
739 }
740
741 wxMouseEvent event( event_type );
742 event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK);
743 event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK);
744 event.m_altDown = (gdk_event->state & GDK_MOD1_MASK);
745 event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK);
746 event.m_leftDown = (gdk_event->state & GDK_BUTTON1_MASK);
747 event.m_middleDown = (gdk_event->state & GDK_BUTTON2_MASK);
748 event.m_rightDown = (gdk_event->state & GDK_BUTTON3_MASK);
749 event.m_x = (long)gdk_event->x;
750 event.m_y = (long)gdk_event->y;
751
752 // Some control don't have their own X window and thus cannot get
753 // any events.
754
755 if (!g_capturing)
756 {
757 wxNode *node = win->GetChildren().First();
758 while (node)
759 {
760 wxWindow *child = (wxWindow*)node->Data();
761
762 if (child->m_isStaticBox)
763 {
764 // wxStaticBox is transparent in the box itself
765 int x = event.m_x;
766 int y = event.m_y;
767 int xx1 = child->m_x;
768 int yy1 = child->m_y;
769 int xx2 = child->m_x + child->m_width;
770 int yy2 = child->m_x + child->m_height;
771
772 // left
773 if (((x >= xx1) && (x <= xx1+10) && (y >= yy1) && (y <= yy2)) ||
774 // right
775 ((x >= xx2-10) && (x <= xx2) && (y >= yy1) && (y <= yy2)) ||
776 // top
777 ((x >= xx1) && (x <= xx2) && (y >= yy1) && (y <= yy1+10)) ||
778 // bottom
779 ((x >= xx1) && (x <= xx2) && (y >= yy2-1) && (y <= yy2)))
780 {
781 win = child;
782 event.m_x -= child->m_x;
783 event.m_y -= child->m_y;
784 break;
785 }
786
787 }
788 else
789 {
790 if ((child->m_wxwindow == (GtkWidget*) NULL) &&
791 (child->m_x <= event.m_x) &&
792 (child->m_y <= event.m_y) &&
793 (child->m_x+child->m_width >= event.m_x) &&
794 (child->m_y+child->m_height >= event.m_y))
795 {
796 win = child;
797 event.m_x -= child->m_x;
798 event.m_y -= child->m_y;
799 break;
800 }
801 }
802 node = node->Next();
803 }
804 }
805
806 event.SetEventObject( win );
807
808 if (win->GetEventHandler()->ProcessEvent( event ))
809 {
810 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "button_release_event" );
811 return TRUE;
812 }
813
814 return FALSE;
815 }
816
817 //-----------------------------------------------------------------------------
818 // "motion_notify_event"
819 //-----------------------------------------------------------------------------
820
821 static gint gtk_window_motion_notify_callback( GtkWidget *widget, GdkEventMotion *gdk_event, wxWindow *win )
822 {
823 if (!win->HasVMT()) return FALSE;
824 if (g_blockEventsOnDrag) return FALSE;
825 if (g_blockEventsOnScroll) return FALSE;
826
827 if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
828
829 if (gdk_event->is_hint)
830 {
831 int x = 0;
832 int y = 0;
833 GdkModifierType state;
834 gdk_window_get_pointer(gdk_event->window, &x, &y, &state);
835 gdk_event->x = x;
836 gdk_event->y = y;
837 gdk_event->state = state;
838 }
839
840 /*
841 printf( "OnMotion from " );
842 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
843 printf( win->GetClassInfo()->GetClassName() );
844 printf( ".\n" );
845 */
846
847 wxMouseEvent event( wxEVT_MOTION );
848 event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK);
849 event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK);
850 event.m_altDown = (gdk_event->state & GDK_MOD1_MASK);
851 event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK);
852 event.m_leftDown = (gdk_event->state & GDK_BUTTON1_MASK);
853 event.m_middleDown = (gdk_event->state & GDK_BUTTON2_MASK);
854 event.m_rightDown = (gdk_event->state & GDK_BUTTON3_MASK);
855
856 event.m_x = (long)gdk_event->x;
857 event.m_y = (long)gdk_event->y;
858
859 // Some control don't have their own X window and thus cannot get
860 // any events.
861
862 if (!g_capturing)
863 {
864 wxNode *node = win->GetChildren().First();
865 while (node)
866 {
867 wxWindow *child = (wxWindow*)node->Data();
868
869 if (child->m_isStaticBox)
870 {
871 // wxStaticBox is transparent in the box itself
872 int x = event.m_x;
873 int y = event.m_y;
874 int xx1 = child->m_x;
875 int yy1 = child->m_y;
876 int xx2 = child->m_x + child->m_width;
877 int yy2 = child->m_x + child->m_height;
878
879 // left
880 if (((x >= xx1) && (x <= xx1+10) && (y >= yy1) && (y <= yy2)) ||
881 // right
882 ((x >= xx2-10) && (x <= xx2) && (y >= yy1) && (y <= yy2)) ||
883 // top
884 ((x >= xx1) && (x <= xx2) && (y >= yy1) && (y <= yy1+10)) ||
885 // bottom
886 ((x >= xx1) && (x <= xx2) && (y >= yy2-1) && (y <= yy2)))
887 {
888 win = child;
889 event.m_x -= child->m_x;
890 event.m_y -= child->m_y;
891 break;
892 }
893
894 }
895 else
896 {
897 if ((child->m_wxwindow == (GtkWidget*) NULL) &&
898 (child->m_x <= event.m_x) &&
899 (child->m_y <= event.m_y) &&
900 (child->m_x+child->m_width >= event.m_x) &&
901 (child->m_y+child->m_height >= event.m_y))
902 {
903 win = child;
904 event.m_x -= child->m_x;
905 event.m_y -= child->m_y;
906 break;
907 }
908 }
909 node = node->Next();
910 }
911 }
912
913 event.SetEventObject( win );
914
915 if (win->GetEventHandler()->ProcessEvent( event ))
916 {
917 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "motion_notify_event" );
918 return TRUE;
919 }
920
921 return FALSE;
922 }
923
924 //-----------------------------------------------------------------------------
925 // "focus_in_event"
926 //-----------------------------------------------------------------------------
927
928 static gint gtk_window_focus_in_callback( GtkWidget *widget, GdkEvent *WXUNUSED(event), wxWindow *win )
929 {
930 if (!win->HasVMT()) return FALSE;
931 if (g_blockEventsOnDrag) return FALSE;
932
933 g_focusWindow = win;
934
935 if (win->m_wxwindow)
936 {
937 if (GTK_WIDGET_CAN_FOCUS(win->m_wxwindow))
938 {
939 GTK_WIDGET_SET_FLAGS (win->m_wxwindow, GTK_HAS_FOCUS);
940 /*
941 printf( "SetFocus flag from " );
942 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
943 printf( win->GetClassInfo()->GetClassName() );
944 printf( ".\n" );
945 */
946 }
947 }
948
949
950 /*
951 printf( "OnSetFocus from " );
952 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
953 printf( win->GetClassInfo()->GetClassName() );
954 printf( " " );
955 printf( WXSTRINGCAST win->GetLabel() );
956 printf( ".\n" );
957 */
958
959 wxFocusEvent event( wxEVT_SET_FOCUS, win->GetId() );
960 event.SetEventObject( win );
961
962 if (win->GetEventHandler()->ProcessEvent( event ))
963 {
964 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "focus_in_event" );
965 return TRUE;
966 }
967
968 return FALSE;
969 }
970
971 //-----------------------------------------------------------------------------
972 // "focus_out_event"
973 //-----------------------------------------------------------------------------
974
975 static gint gtk_window_focus_out_callback( GtkWidget *widget, GdkEvent *WXUNUSED(event), wxWindow *win )
976 {
977 if (!win->HasVMT()) return FALSE;
978 if (g_blockEventsOnDrag) return FALSE;
979
980 if (win->m_wxwindow)
981 {
982 if (GTK_WIDGET_CAN_FOCUS(win->m_wxwindow))
983 GTK_WIDGET_UNSET_FLAGS (win->m_wxwindow, GTK_HAS_FOCUS);
984 }
985
986 /*
987 printf( "OnKillFocus from " );
988 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
989 printf( win->GetClassInfo()->GetClassName() );
990 printf( ".\n" );
991 */
992
993 wxFocusEvent event( wxEVT_KILL_FOCUS, win->GetId() );
994 event.SetEventObject( win );
995
996 if (win->GetEventHandler()->ProcessEvent( event ))
997 {
998 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "focus_out_event" );
999 return TRUE;
1000 }
1001
1002 return FALSE;
1003 }
1004
1005 //-----------------------------------------------------------------------------
1006 // "enter_notify_event"
1007 //-----------------------------------------------------------------------------
1008
1009 static gint gtk_window_enter_callback( GtkWidget *widget, GdkEventCrossing *gdk_event, wxWindow *win )
1010 {
1011 if (!win->HasVMT()) return FALSE;
1012 if (g_blockEventsOnDrag) return FALSE;
1013
1014 if (widget->window != gdk_event->window) return FALSE;
1015
1016 if ((widget->window) && (win->m_cursor))
1017 gdk_window_set_cursor( widget->window, win->m_cursor->GetCursor() );
1018
1019 /*
1020 printf( "OnEnter from " );
1021 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1022 printf( win->GetClassInfo()->GetClassName() );
1023 printf( ".\n" );
1024 */
1025
1026 wxMouseEvent event( wxEVT_ENTER_WINDOW );
1027 event.SetEventObject( win );
1028
1029 int x = 0;
1030 int y = 0;
1031 GdkModifierType state = (GdkModifierType)0;
1032
1033 gdk_window_get_pointer( widget->window, &x, &y, &state );
1034
1035 event.m_shiftDown = (state & GDK_SHIFT_MASK);
1036 event.m_controlDown = (state & GDK_CONTROL_MASK);
1037 event.m_altDown = (state & GDK_MOD1_MASK);
1038 event.m_metaDown = (state & GDK_MOD2_MASK);
1039 event.m_leftDown = (state & GDK_BUTTON1_MASK);
1040 event.m_middleDown = (state & GDK_BUTTON2_MASK);
1041 event.m_rightDown = (state & GDK_BUTTON3_MASK);
1042
1043 event.m_x = (long)x;
1044 event.m_y = (long)y;
1045
1046 if (win->GetEventHandler()->ProcessEvent( event ))
1047 {
1048 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "enter_notify_event" );
1049 return TRUE;
1050 }
1051
1052 return FALSE;
1053 }
1054
1055 //-----------------------------------------------------------------------------
1056 // "leave_notify_event"
1057 //-----------------------------------------------------------------------------
1058
1059 static gint gtk_window_leave_callback( GtkWidget *widget, GdkEventCrossing *gdk_event, wxWindow *win )
1060 {
1061 if (!win->HasVMT()) return FALSE;
1062 if (g_blockEventsOnDrag) return FALSE;
1063
1064 if (widget->window != gdk_event->window) return FALSE;
1065
1066 if ((widget->window) && (win->m_cursor))
1067 gdk_window_set_cursor( widget->window, wxSTANDARD_CURSOR->GetCursor() );
1068
1069 /*
1070 printf( "OnLeave from " );
1071 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1072 printf( win->GetClassInfo()->GetClassName() );
1073 printf( ".\n" );
1074 */
1075
1076 wxMouseEvent event( wxEVT_LEAVE_WINDOW );
1077 event.SetEventObject( win );
1078
1079 int x = 0;
1080 int y = 0;
1081 GdkModifierType state = (GdkModifierType)0;
1082
1083 gdk_window_get_pointer( widget->window, &x, &y, &state );
1084
1085 event.m_shiftDown = (state & GDK_SHIFT_MASK);
1086 event.m_controlDown = (state & GDK_CONTROL_MASK);
1087 event.m_altDown = (state & GDK_MOD1_MASK);
1088 event.m_metaDown = (state & GDK_MOD2_MASK);
1089 event.m_leftDown = (state & GDK_BUTTON1_MASK);
1090 event.m_middleDown = (state & GDK_BUTTON2_MASK);
1091 event.m_rightDown = (state & GDK_BUTTON3_MASK);
1092
1093 event.m_x = (long)x;
1094 event.m_y = (long)y;
1095
1096 if (win->GetEventHandler()->ProcessEvent( event ))
1097 {
1098 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "leave_notify_event" );
1099 return TRUE;
1100 }
1101
1102 return FALSE;
1103 }
1104
1105 //-----------------------------------------------------------------------------
1106 // "value_changed" from m_vAdjust
1107 //-----------------------------------------------------------------------------
1108
1109 static void gtk_window_vscroll_callback( GtkWidget *WXUNUSED(widget), wxWindow *win )
1110 {
1111 if (g_blockEventsOnDrag) return;
1112
1113 /*
1114 printf( "OnVScroll from " );
1115 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1116 printf( win->GetClassInfo()->GetClassName() );
1117 printf( ".\n" );
1118 */
1119
1120 if (!win->HasVMT()) return;
1121
1122 float diff = win->m_vAdjust->value - win->m_oldVerticalPos;
1123 if (fabs(diff) < 0.2) return;
1124 win->m_oldVerticalPos = win->m_vAdjust->value;
1125
1126 wxEventType command = wxEVT_NULL;
1127
1128 float line_step = win->m_vAdjust->step_increment;
1129 float page_step = win->m_vAdjust->page_increment;
1130
1131 if (win->m_isScrolling)
1132 {
1133 command = wxEVT_SCROLL_THUMBTRACK;
1134 }
1135 else
1136 {
1137 if (fabs(win->m_vAdjust->value-win->m_vAdjust->lower) < 0.2) command = wxEVT_SCROLL_BOTTOM;
1138 else if (fabs(win->m_vAdjust->value-win->m_vAdjust->upper) < 0.2) command = wxEVT_SCROLL_TOP;
1139 else if (fabs(diff-line_step) < 0.2) command = wxEVT_SCROLL_LINEDOWN;
1140 else if (fabs(diff+line_step) < 0.2) command = wxEVT_SCROLL_LINEUP;
1141 else if (fabs(diff-page_step) < 0.2) command = wxEVT_SCROLL_PAGEDOWN;
1142 else if (fabs(diff+page_step) < 0.2) command = wxEVT_SCROLL_PAGEUP;
1143 else command = wxEVT_SCROLL_THUMBTRACK;
1144 }
1145
1146 int value = (int)(win->m_vAdjust->value+0.5);
1147
1148 wxScrollEvent event( command, win->GetId(), value, wxVERTICAL );
1149 event.SetEventObject( win );
1150 win->GetEventHandler()->ProcessEvent( event );
1151 }
1152
1153 //-----------------------------------------------------------------------------
1154 // "value_changed" from m_hAdjust
1155 //-----------------------------------------------------------------------------
1156
1157 static void gtk_window_hscroll_callback( GtkWidget *WXUNUSED(widget), wxWindow *win )
1158 {
1159 if (g_blockEventsOnDrag) return;
1160
1161 /*
1162 printf( "OnHScroll from " );
1163 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1164 printf( win->GetClassInfo()->GetClassName() );
1165 printf( ".\n" );
1166 */
1167
1168 if (!win->HasVMT()) return;
1169
1170 float diff = win->m_hAdjust->value - win->m_oldHorizontalPos;
1171 if (fabs(diff) < 0.2) return;
1172 win->m_oldHorizontalPos = win->m_hAdjust->value;
1173
1174 wxEventType command = wxEVT_NULL;
1175
1176 float line_step = win->m_hAdjust->step_increment;
1177 float page_step = win->m_hAdjust->page_increment;
1178
1179 if (win->m_isScrolling)
1180 {
1181 command = wxEVT_SCROLL_THUMBTRACK;
1182 }
1183 else
1184 {
1185 if (fabs(win->m_hAdjust->value-win->m_hAdjust->lower) < 0.2) command = wxEVT_SCROLL_BOTTOM;
1186 else if (fabs(win->m_hAdjust->value-win->m_hAdjust->upper) < 0.2) command = wxEVT_SCROLL_TOP;
1187 else if (fabs(diff-line_step) < 0.2) command = wxEVT_SCROLL_LINEDOWN;
1188 else if (fabs(diff+line_step) < 0.2) command = wxEVT_SCROLL_LINEUP;
1189 else if (fabs(diff-page_step) < 0.2) command = wxEVT_SCROLL_PAGEDOWN;
1190 else if (fabs(diff+page_step) < 0.2) command = wxEVT_SCROLL_PAGEUP;
1191 else command = wxEVT_SCROLL_THUMBTRACK;
1192 }
1193
1194 int value = (int)(win->m_hAdjust->value+0.5);
1195
1196 wxScrollEvent event( command, win->GetId(), value, wxHORIZONTAL );
1197 event.SetEventObject( win );
1198 win->GetEventHandler()->ProcessEvent( event );
1199 }
1200
1201 //-----------------------------------------------------------------------------
1202 // "changed" from m_vAdjust
1203 //-----------------------------------------------------------------------------
1204
1205 static void gtk_window_vscroll_change_callback( GtkWidget *WXUNUSED(widget), wxWindow *win )
1206 {
1207 if (g_blockEventsOnDrag) return;
1208
1209 /*
1210 printf( "OnVScroll change from " );
1211 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1212 printf( win->GetClassInfo()->GetClassName() );
1213 printf( ".\n" );
1214 */
1215
1216 if (!win->HasVMT()) return;
1217
1218 wxEventType command = wxEVT_SCROLL_THUMBTRACK;
1219 int value = (int)(win->m_vAdjust->value+0.5);
1220
1221 wxScrollEvent event( command, win->GetId(), value, wxVERTICAL );
1222 event.SetEventObject( win );
1223 win->GetEventHandler()->ProcessEvent( event );
1224 }
1225
1226 //-----------------------------------------------------------------------------
1227 // "changed" from m_hAdjust
1228 //-----------------------------------------------------------------------------
1229
1230 static void gtk_window_hscroll_change_callback( GtkWidget *WXUNUSED(widget), wxWindow *win )
1231 {
1232 if (g_blockEventsOnDrag) return;
1233
1234 /*
1235 printf( "OnHScroll change from " );
1236 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1237 printf( win->GetClassInfo()->GetClassName() );
1238 printf( ".\n" );
1239 */
1240
1241 if (!win->HasVMT()) return;
1242
1243 wxEventType command = wxEVT_SCROLL_THUMBTRACK;
1244 int value = (int)(win->m_hAdjust->value+0.5);
1245
1246 wxScrollEvent event( command, win->GetId(), value, wxHORIZONTAL );
1247 event.SetEventObject( win );
1248 win->GetEventHandler()->ProcessEvent( event );
1249 }
1250
1251 //-----------------------------------------------------------------------------
1252 // "button_press_event" from scrollbar
1253 //-----------------------------------------------------------------------------
1254
1255 static gint gtk_scrollbar_button_press_callback( GtkRange *WXUNUSED(widget),
1256 GdkEventButton *WXUNUSED(gdk_event),
1257 wxWindow *win )
1258 {
1259 // don't test here as we can release the mouse while being over
1260 // a different window then the slider
1261 //
1262 // if (gdk_event->window != widget->slider) return FALSE;
1263
1264 win->m_isScrolling = TRUE;
1265 g_blockEventsOnScroll = TRUE;
1266
1267 return FALSE;
1268 }
1269
1270 //-----------------------------------------------------------------------------
1271 // "button_release_event" from scrollbar
1272 //-----------------------------------------------------------------------------
1273
1274 static gint gtk_scrollbar_button_release_callback( GtkRange *widget,
1275 GdkEventButton *WXUNUSED(gdk_event),
1276 wxWindow *win )
1277 {
1278
1279 // don't test here as we can release the mouse while being over
1280 // a different window then the slider
1281 //
1282 // if (gdk_event->window != widget->slider) return FALSE;
1283
1284 GtkScrolledWindow *s_window = GTK_SCROLLED_WINDOW(win->m_widget);
1285
1286 if (widget == GTK_RANGE(s_window->vscrollbar))
1287 gtk_signal_emit_by_name( GTK_OBJECT(win->m_hAdjust), "value_changed" );
1288 else
1289 gtk_signal_emit_by_name( GTK_OBJECT(win->m_vAdjust), "value_changed" );
1290
1291 win->m_isScrolling = FALSE;
1292 g_blockEventsOnScroll = FALSE;
1293
1294 return FALSE;
1295 }
1296
1297 //-----------------------------------------------------------------------------
1298 // "realize" from m_widget
1299 //-----------------------------------------------------------------------------
1300
1301 /* we cannot set colours, fonts and cursors before the widget has
1302 been realized, so we do this directly after realization */
1303
1304 static gint
1305 gtk_window_realized_callback( GtkWidget *widget, wxWindow *win )
1306 {
1307 if (win->m_font != *wxSWISS_FONT)
1308 {
1309 wxFont font( win->m_font );
1310 win->m_font = wxNullFont;
1311 win->SetFont( font );
1312 }
1313
1314 if (win->m_backgroundColour != wxSystemSettings::GetSystemColour( wxSYS_COLOUR_BTNFACE ))
1315 {
1316 wxColour bg( win->m_backgroundColour );
1317 win->SetBackgroundColour( wxNullColour );
1318 win->SetBackgroundColour( bg );
1319 }
1320
1321 if (win->m_foregroundColour != *wxBLACK)
1322 {
1323 wxColour fg( win->m_foregroundColour );
1324 win->SetForegroundColour( wxNullColour );
1325 win->SetForegroundColour( fg );
1326 }
1327
1328 return FALSE;
1329 }
1330
1331 //-----------------------------------------------------------------------------
1332 // InsertChild for wxWindow.
1333 //-----------------------------------------------------------------------------
1334
1335 /* Callback for wxWindow. This very strange beast has to be used because
1336 * C++ has no virtual methods in a constructor. We have to emulate a
1337 * virtual function here as wxNotebook requires a different way to insert
1338 * a child in it. I had opted for creating a wxNotebookPage window class
1339 * which would have made this superfluous (such in the MDI window system),
1340 * but no-one was listening to me... */
1341
1342 static void wxInsertChildInWindow( wxWindow* parent, wxWindow* child )
1343 {
1344 gtk_myfixed_put( GTK_MYFIXED(parent->m_wxwindow),
1345 GTK_WIDGET(child->m_widget),
1346 child->m_x,
1347 child->m_y );
1348
1349 gtk_widget_set_usize( GTK_WIDGET(child->m_widget),
1350 child->m_width,
1351 child->m_height );
1352
1353 if (parent->m_windowStyle & wxTAB_TRAVERSAL)
1354 {
1355 /* we now allow a window to get the focus as long as it
1356 doesn't have any children. */
1357 GTK_WIDGET_UNSET_FLAGS( parent->m_wxwindow, GTK_CAN_FOCUS );
1358 }
1359 }
1360
1361 //-----------------------------------------------------------------------------
1362 // global functions
1363 //-----------------------------------------------------------------------------
1364
1365 wxWindow* wxGetActiveWindow()
1366 {
1367 return g_focusWindow;
1368 }
1369
1370 //-----------------------------------------------------------------------------
1371 // wxWindow
1372 //-----------------------------------------------------------------------------
1373
1374 IMPLEMENT_DYNAMIC_CLASS(wxWindow,wxEvtHandler)
1375
1376 BEGIN_EVENT_TABLE(wxWindow, wxEvtHandler)
1377 EVT_SIZE(wxWindow::OnSize)
1378 EVT_SYS_COLOUR_CHANGED(wxWindow::OnSysColourChanged)
1379 EVT_INIT_DIALOG(wxWindow::OnInitDialog)
1380 EVT_KEY_DOWN(wxWindow::OnKeyDown)
1381 END_EVENT_TABLE()
1382
1383 void wxWindow::Init()
1384 {
1385 m_isWindow = TRUE;
1386
1387 m_widget = (GtkWidget *) NULL;
1388 m_wxwindow = (GtkWidget *) NULL;
1389 m_parent = (wxWindow *) NULL;
1390 m_children.DeleteContents( FALSE );
1391
1392 m_x = 0;
1393 m_y = 0;
1394 m_width = 0;
1395 m_height = 0;
1396 m_minWidth = -1;
1397 m_minHeight = -1;
1398 m_maxWidth = -1;
1399 m_maxHeight = -1;
1400
1401 m_retCode = 0;
1402
1403 m_eventHandler = this;
1404 m_windowValidator = (wxValidator *) NULL;
1405
1406 m_windowId = -1;
1407
1408 m_cursor = (wxCursor *) NULL;
1409 m_font = *wxSWISS_FONT;
1410 m_windowStyle = 0;
1411 m_windowName = "noname";
1412
1413 m_constraints = (wxLayoutConstraints *) NULL;
1414 m_constraintsInvolvedIn = (wxList *) NULL;
1415 m_windowSizer = (wxSizer *) NULL;
1416 m_sizerParent = (wxWindow *) NULL;
1417 m_autoLayout = FALSE;
1418
1419 m_sizeSet = FALSE;
1420 m_hasVMT = FALSE;
1421 m_needParent = TRUE;
1422
1423 m_hasScrolling = FALSE;
1424 m_isScrolling = FALSE;
1425 m_hAdjust = (GtkAdjustment*) NULL;
1426 m_vAdjust = (GtkAdjustment*) NULL;
1427 m_oldHorizontalPos = 0.0;
1428 m_oldVerticalPos = 0.0;
1429
1430 m_isShown = FALSE;
1431 m_isEnabled = TRUE;
1432
1433 #if wxUSE_DRAG_AND_DROP
1434 m_dropTarget = (wxDropTarget*) NULL;
1435 #endif
1436 m_resizing = FALSE;
1437 m_scrollGC = (GdkGC*) NULL;
1438 m_widgetStyle = (GtkStyle*) NULL;
1439
1440 m_insertCallback = wxInsertChildInWindow;
1441
1442 m_clientObject = (wxClientData*) NULL;
1443 m_clientData = NULL;
1444
1445 m_isStaticBox = FALSE;
1446 m_acceptsFocus = FALSE;
1447
1448 #if wxUSE_TOOLTIPS
1449 m_toolTip = (wxToolTip*) NULL;
1450 #endif // wxUSE_TOOLTIPS
1451 }
1452
1453 wxWindow::wxWindow()
1454 {
1455 Init();
1456 }
1457
1458 wxWindow::wxWindow( wxWindow *parent, wxWindowID id,
1459 const wxPoint &pos, const wxSize &size,
1460 long style, const wxString &name )
1461 {
1462 Init();
1463
1464 Create( parent, id, pos, size, style, name );
1465 }
1466
1467 bool wxWindow::Create( wxWindow *parent, wxWindowID id,
1468 const wxPoint &pos, const wxSize &size,
1469 long style, const wxString &name )
1470 {
1471 wxASSERT_MSG( m_isWindow, _T("Init() must have been called before!") );
1472
1473 PreCreation( parent, id, pos, size, style, name );
1474
1475 m_widget = gtk_scrolled_window_new( (GtkAdjustment *) NULL, (GtkAdjustment *) NULL );
1476 GTK_WIDGET_UNSET_FLAGS( m_widget, GTK_CAN_FOCUS );
1477
1478 GtkScrolledWindow *s_window = GTK_SCROLLED_WINDOW(m_widget);
1479
1480 GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT(m_widget)->klass );
1481 scroll_class->scrollbar_spacing = 0;
1482
1483 gtk_scrolled_window_set_policy( s_window, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC );
1484
1485 m_oldHorizontalPos = 0.0;
1486 m_oldVerticalPos = 0.0;
1487
1488 m_hAdjust = gtk_range_get_adjustment( GTK_RANGE(s_window->hscrollbar) );
1489 m_vAdjust = gtk_range_get_adjustment( GTK_RANGE(s_window->vscrollbar) );
1490
1491 m_wxwindow = gtk_myfixed_new();
1492 gtk_widget_show( m_wxwindow );
1493
1494 gtk_container_add( GTK_CONTAINER(m_widget), m_wxwindow );
1495
1496 #if (GTK_MINOR_VERSION > 0)
1497 GtkMyFixed *myfixed = GTK_MYFIXED(m_wxwindow);
1498
1499 if (m_windowStyle & wxRAISED_BORDER)
1500 {
1501 gtk_myfixed_set_shadow_type( myfixed, GTK_SHADOW_OUT );
1502 }
1503 else if (m_windowStyle & wxSUNKEN_BORDER)
1504 {
1505 gtk_myfixed_set_shadow_type( myfixed, GTK_SHADOW_IN );
1506 }
1507 else
1508 {
1509 gtk_myfixed_set_shadow_type( myfixed, GTK_SHADOW_NONE );
1510 }
1511 #else
1512 GtkViewport *viewport = GTK_VIEWPORT(s_window->viewport);
1513
1514 if (m_windowStyle & wxRAISED_BORDER)
1515 {
1516 gtk_viewport_set_shadow_type( viewport, GTK_SHADOW_OUT );
1517 }
1518 else if (m_windowStyle & wxSUNKEN_BORDER)
1519 {
1520 gtk_viewport_set_shadow_type( viewport, GTK_SHADOW_IN );
1521 }
1522 else
1523 {
1524 gtk_viewport_set_shadow_type( viewport, GTK_SHADOW_NONE );
1525 }
1526 #endif
1527
1528 if (m_windowStyle & wxTAB_TRAVERSAL)
1529 {
1530 /* we now allow a window to get the focus as long as it
1531 doesn't have any children. */
1532 GTK_WIDGET_SET_FLAGS( m_wxwindow, GTK_CAN_FOCUS );
1533 m_acceptsFocus = FALSE;
1534 }
1535 else
1536 {
1537 GTK_WIDGET_SET_FLAGS( m_wxwindow, GTK_CAN_FOCUS );
1538 m_acceptsFocus = TRUE;
1539 }
1540
1541 #if (GTK_MINOR_VERSION == 0)
1542 // shut the viewport up
1543 gtk_viewport_set_hadjustment( viewport, (GtkAdjustment*) gtk_adjustment_new( 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) );
1544 gtk_viewport_set_vadjustment( viewport, (GtkAdjustment*) gtk_adjustment_new( 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) );
1545 #endif
1546
1547 // I _really_ don't want scrollbars in the beginning
1548 m_vAdjust->lower = 0.0;
1549 m_vAdjust->upper = 1.0;
1550 m_vAdjust->value = 0.0;
1551 m_vAdjust->step_increment = 1.0;
1552 m_vAdjust->page_increment = 1.0;
1553 m_vAdjust->page_size = 5.0;
1554 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust), "changed" );
1555 m_hAdjust->lower = 0.0;
1556 m_hAdjust->upper = 1.0;
1557 m_hAdjust->value = 0.0;
1558 m_hAdjust->step_increment = 1.0;
1559 m_hAdjust->page_increment = 1.0;
1560 m_hAdjust->page_size = 5.0;
1561 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust), "changed" );
1562
1563 // these handlers block mouse events to any window during scrolling
1564 // such as motion events and prevent GTK and wxWindows from fighting
1565 // over where the slider should be
1566
1567 gtk_signal_connect( GTK_OBJECT(s_window->vscrollbar), "button_press_event",
1568 (GtkSignalFunc)gtk_scrollbar_button_press_callback, (gpointer) this );
1569
1570 gtk_signal_connect( GTK_OBJECT(s_window->hscrollbar), "button_press_event",
1571 (GtkSignalFunc)gtk_scrollbar_button_press_callback, (gpointer) this );
1572
1573 gtk_signal_connect( GTK_OBJECT(s_window->vscrollbar), "button_release_event",
1574 (GtkSignalFunc)gtk_scrollbar_button_release_callback, (gpointer) this );
1575
1576 gtk_signal_connect( GTK_OBJECT(s_window->hscrollbar), "button_release_event",
1577 (GtkSignalFunc)gtk_scrollbar_button_release_callback, (gpointer) this );
1578
1579 // these handlers get notified when screen updates are required either when
1580 // scrolling or when the window size (and therefore scrollbar configuration)
1581 // has changed
1582
1583 gtk_signal_connect( GTK_OBJECT(m_hAdjust), "value_changed",
1584 (GtkSignalFunc) gtk_window_hscroll_callback, (gpointer) this );
1585 gtk_signal_connect( GTK_OBJECT(m_vAdjust), "value_changed",
1586 (GtkSignalFunc) gtk_window_vscroll_callback, (gpointer) this );
1587
1588 gtk_signal_connect( GTK_OBJECT(m_hAdjust), "changed",
1589 (GtkSignalFunc) gtk_window_hscroll_change_callback, (gpointer) this );
1590 gtk_signal_connect(GTK_OBJECT(m_vAdjust), "changed",
1591 (GtkSignalFunc) gtk_window_vscroll_change_callback, (gpointer) this );
1592
1593 if (m_parent) m_parent->AddChild( this );
1594
1595 (m_parent->m_insertCallback)( m_parent, this );
1596
1597 PostCreation();
1598
1599 Show( TRUE );
1600
1601 return TRUE;
1602 }
1603
1604 wxWindow::~wxWindow()
1605 {
1606 m_hasVMT = FALSE;
1607
1608 #if wxUSE_DRAG_AND_DROP
1609 if (m_dropTarget)
1610 {
1611 delete m_dropTarget;
1612 m_dropTarget = (wxDropTarget*) NULL;
1613 }
1614 #endif
1615
1616 #if wxUSE_TOOLTIPS
1617 if (m_toolTip)
1618 {
1619 delete m_toolTip;
1620 m_toolTip = (wxToolTip*) NULL;
1621 }
1622 #endif // wxUSE_TOOLTIPS
1623
1624 if (m_widget) Show( FALSE );
1625
1626 DestroyChildren();
1627
1628 if (m_parent) m_parent->RemoveChild( this );
1629
1630 if (m_widgetStyle) gtk_style_unref( m_widgetStyle );
1631
1632 if (m_scrollGC) gdk_gc_unref( m_scrollGC );
1633
1634 if (m_wxwindow) gtk_widget_destroy( m_wxwindow );
1635
1636 if (m_widget) gtk_widget_destroy( m_widget );
1637
1638 if (m_cursor) delete m_cursor;
1639
1640 DeleteRelatedConstraints();
1641 if (m_constraints)
1642 {
1643 /* This removes any dangling pointers to this window
1644 * in other windows' constraintsInvolvedIn lists. */
1645 UnsetConstraints(m_constraints);
1646 delete m_constraints;
1647 m_constraints = (wxLayoutConstraints *) NULL;
1648 }
1649
1650 if (m_windowSizer)
1651 {
1652 delete m_windowSizer;
1653 m_windowSizer = (wxSizer *) NULL;
1654 }
1655 /* If this is a child of a sizer, remove self from parent */
1656 if (m_sizerParent) m_sizerParent->RemoveChild((wxWindow *)this);
1657
1658 /* Just in case the window has been Closed, but
1659 * we're then deleting immediately: don't leave
1660 * dangling pointers. */
1661 wxPendingDelete.DeleteObject(this);
1662
1663 /* Just in case we've loaded a top-level window via
1664 * wxWindow::LoadNativeDialog but we weren't a dialog
1665 * class */
1666 wxTopLevelWindows.DeleteObject(this);
1667
1668 if (m_windowValidator) delete m_windowValidator;
1669
1670 if (m_clientObject) delete m_clientObject;
1671 }
1672
1673 void wxWindow::PreCreation( wxWindow *parent, wxWindowID id,
1674 const wxPoint &pos, const wxSize &size,
1675 long style, const wxString &name )
1676 {
1677 wxASSERT_MSG( (!m_needParent) || (parent), _T("Need complete parent.") );
1678
1679 m_widget = (GtkWidget*) NULL;
1680 m_wxwindow = (GtkWidget*) NULL;
1681 m_hasVMT = FALSE;
1682 m_parent = parent;
1683 m_children.DeleteContents( FALSE );
1684
1685 m_width = size.x;
1686 if (m_width == -1) m_width = 20;
1687 m_height = size.y;
1688 if (m_height == -1) m_height = 20;
1689
1690 m_x = (int)pos.x;
1691 m_y = (int)pos.y;
1692
1693 if (!m_needParent) /* some reasonable defaults */
1694 {
1695 if (m_x == -1)
1696 {
1697 m_x = (gdk_screen_width () - m_width) / 2;
1698 if (m_x < 10) m_x = 10;
1699 }
1700 if (m_y == -1)
1701 {
1702 m_y = (gdk_screen_height () - m_height) / 2;
1703 if (m_y < 10) m_y = 10;
1704 }
1705 }
1706
1707 m_minWidth = -1;
1708 m_minHeight = -1;
1709 m_maxWidth = -1;
1710 m_maxHeight = -1;
1711
1712 m_retCode = 0;
1713
1714 m_eventHandler = this;
1715
1716 m_windowId = id == -1 ? wxNewId() : id;
1717
1718 m_sizeSet = FALSE;
1719
1720 m_cursor = new wxCursor( wxCURSOR_ARROW );
1721 m_font = *wxSWISS_FONT;
1722 m_backgroundColour = wxSystemSettings::GetSystemColour( wxSYS_COLOUR_BTNFACE );
1723 m_foregroundColour = *wxBLACK;
1724 m_windowStyle = style;
1725 m_windowName = name;
1726
1727 m_constraints = (wxLayoutConstraints *) NULL;
1728 m_constraintsInvolvedIn = (wxList *) NULL;
1729 m_windowSizer = (wxSizer *) NULL;
1730 m_sizerParent = (wxWindow *) NULL;
1731 m_autoLayout = FALSE;
1732
1733 m_hasScrolling = FALSE;
1734 m_isScrolling = FALSE;
1735 m_hAdjust = (GtkAdjustment *) NULL;
1736 m_vAdjust = (GtkAdjustment *) NULL;
1737 m_oldHorizontalPos = 0.0;
1738 m_oldVerticalPos = 0.0;
1739
1740 m_isShown = FALSE;
1741 m_isEnabled = TRUE;
1742
1743 #if wxUSE_DRAG_AND_DROP
1744 m_dropTarget = (wxDropTarget *) NULL;
1745 #endif
1746 m_resizing = FALSE;
1747 m_windowValidator = (wxValidator *) NULL;
1748 m_scrollGC = (GdkGC*) NULL;
1749 m_widgetStyle = (GtkStyle*) NULL;
1750
1751 m_clientObject = (wxClientData*)NULL;
1752 m_clientData = NULL;
1753
1754 m_isStaticBox = FALSE;
1755
1756 #if wxUSE_TOOLTIPS
1757 m_toolTip = (wxToolTip*) NULL;
1758 #endif // wxUSE_TOOLTIPS
1759 }
1760
1761 void wxWindow::PostCreation()
1762 {
1763 wxASSERT_MSG( (m_widget != NULL), _T("invalid window") );
1764
1765 if (m_wxwindow)
1766 {
1767 /* these get reported to wxWindows -> wxPaintEvent */
1768 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "expose_event",
1769 GTK_SIGNAL_FUNC(gtk_window_expose_callback), (gpointer)this );
1770
1771 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "draw",
1772 GTK_SIGNAL_FUNC(gtk_window_draw_callback), (gpointer)this );
1773
1774 #if (GTK_MINOR_VERSION > 0)
1775 /* these are called when the "sunken" or "raised" borders are drawn */
1776 gtk_signal_connect( GTK_OBJECT(m_widget), "expose_event",
1777 GTK_SIGNAL_FUNC(gtk_window_own_expose_callback), (gpointer)this );
1778
1779 gtk_signal_connect( GTK_OBJECT(m_widget), "draw",
1780 GTK_SIGNAL_FUNC(gtk_window_own_draw_callback), (gpointer)this );
1781 #endif
1782 }
1783
1784 ConnectWidget( GetConnectWidget() );
1785
1786 /* we cannot set colours, fonts and cursors before the widget has
1787 been realized, so we do this directly after realization */
1788
1789 gtk_signal_connect( GTK_OBJECT(m_widget), "realize",
1790 GTK_SIGNAL_FUNC(gtk_window_realized_callback), (gpointer) this );
1791
1792 m_hasVMT = TRUE;
1793 }
1794
1795 void wxWindow::ConnectWidget( GtkWidget *widget )
1796 {
1797 gtk_signal_connect( GTK_OBJECT(widget), "key_press_event",
1798 GTK_SIGNAL_FUNC(gtk_window_key_press_callback), (gpointer)this );
1799
1800 gtk_signal_connect( GTK_OBJECT(widget), "key_release_event",
1801 GTK_SIGNAL_FUNC(gtk_window_key_release_callback), (gpointer)this );
1802
1803 gtk_signal_connect( GTK_OBJECT(widget), "button_press_event",
1804 GTK_SIGNAL_FUNC(gtk_window_button_press_callback), (gpointer)this );
1805
1806 gtk_signal_connect( GTK_OBJECT(widget), "button_release_event",
1807 GTK_SIGNAL_FUNC(gtk_window_button_release_callback), (gpointer)this );
1808
1809 gtk_signal_connect( GTK_OBJECT(widget), "motion_notify_event",
1810 GTK_SIGNAL_FUNC(gtk_window_motion_notify_callback), (gpointer)this );
1811
1812 gtk_signal_connect( GTK_OBJECT(widget), "focus_in_event",
1813 GTK_SIGNAL_FUNC(gtk_window_focus_in_callback), (gpointer)this );
1814
1815 gtk_signal_connect( GTK_OBJECT(widget), "focus_out_event",
1816 GTK_SIGNAL_FUNC(gtk_window_focus_out_callback), (gpointer)this );
1817
1818 gtk_signal_connect( GTK_OBJECT(widget), "enter_notify_event",
1819 GTK_SIGNAL_FUNC(gtk_window_enter_callback), (gpointer)this );
1820
1821 gtk_signal_connect( GTK_OBJECT(widget), "leave_notify_event",
1822 GTK_SIGNAL_FUNC(gtk_window_leave_callback), (gpointer)this );
1823 }
1824
1825 bool wxWindow::HasVMT()
1826 {
1827 return m_hasVMT;
1828 }
1829
1830 bool wxWindow::Close( bool force )
1831 {
1832 wxASSERT_MSG( (m_widget != NULL), _T("invalid window") );
1833
1834 wxCloseEvent event(wxEVT_CLOSE_WINDOW, m_windowId);
1835 event.SetEventObject(this);
1836 event.SetCanVeto(!force);
1837
1838 /* return FALSE if window wasn't closed because the application vetoed the
1839 * close event */
1840 return GetEventHandler()->ProcessEvent(event) && !event.GetVeto();
1841 }
1842
1843 bool wxWindow::Destroy()
1844 {
1845 wxASSERT_MSG( (m_widget != NULL), _T("invalid window") );
1846
1847 m_hasVMT = FALSE;
1848 delete this;
1849 return TRUE;
1850 }
1851
1852 bool wxWindow::DestroyChildren()
1853 {
1854 wxNode *node;
1855 while ((node = m_children.First()) != (wxNode *)NULL)
1856 {
1857 wxWindow *child;
1858 if ((child = (wxWindow *)node->Data()) != (wxWindow *)NULL)
1859 {
1860 delete child;
1861 if (m_children.Member(child)) delete node;
1862 }
1863 }
1864 return TRUE;
1865 }
1866
1867 void wxWindow::PrepareDC( wxDC &WXUNUSED(dc) )
1868 {
1869 // are we to set fonts here ?
1870 }
1871
1872 void wxWindow::DoSetSize( int x, int y, int width, int height, int sizeFlags )
1873 {
1874 wxASSERT_MSG( (m_widget != NULL), _T("invalid window") );
1875 wxASSERT_MSG( (m_parent != NULL), _T("wxWindow::SetSize requires parent.\n") );
1876
1877 if (m_resizing) return; /* I don't like recursions */
1878 m_resizing = TRUE;
1879
1880 if (m_parent->m_wxwindow == NULL) /* i.e. wxNotebook */
1881 {
1882 /* don't set the size for children of wxNotebook, just take the values. */
1883 m_x = x;
1884 m_y = y;
1885 m_width = width;
1886 m_height = height;
1887 }
1888 else
1889 {
1890 int old_width = m_width;
1891 int old_height = m_height;
1892
1893 if ((sizeFlags & wxSIZE_USE_EXISTING) == wxSIZE_USE_EXISTING)
1894 {
1895 if (x != -1) m_x = x;
1896 if (y != -1) m_y = y;
1897 if (width != -1) m_width = width;
1898 if (height != -1) m_height = height;
1899 }
1900 else
1901 {
1902 m_x = x;
1903 m_y = y;
1904 m_width = width;
1905 m_height = height;
1906 }
1907
1908 if ((sizeFlags & wxSIZE_AUTO_WIDTH) == wxSIZE_AUTO_WIDTH)
1909 {
1910 if (width == -1) m_width = 80;
1911 }
1912
1913 if ((sizeFlags & wxSIZE_AUTO_HEIGHT) == wxSIZE_AUTO_HEIGHT)
1914 {
1915 if (height == -1) m_height = 26;
1916 }
1917
1918 if ((m_minWidth != -1) && (m_width < m_minWidth)) m_width = m_minWidth;
1919 if ((m_minHeight != -1) && (m_height < m_minHeight)) m_height = m_minHeight;
1920 if ((m_maxWidth != -1) && (m_width > m_maxWidth)) m_width = m_maxWidth;
1921 if ((m_maxHeight != -1) && (m_height > m_maxHeight)) m_height = m_maxHeight;
1922
1923 if (GTK_WIDGET_HAS_DEFAULT(m_widget))
1924 {
1925 /* the default button has a border around it */
1926 int border = 5;
1927
1928 gtk_myfixed_move( GTK_MYFIXED(m_parent->m_wxwindow), m_widget, m_x-border, m_y-border );
1929
1930 gtk_widget_set_usize( m_widget, m_width+2*border, m_height+2*border );
1931 }
1932 else
1933 {
1934 gtk_myfixed_move( GTK_MYFIXED(m_parent->m_wxwindow), m_widget, m_x, m_y );
1935
1936 if ((old_width != m_width) || (old_height != m_height))
1937 gtk_widget_set_usize( m_widget, m_width, m_height );
1938 }
1939 }
1940
1941 m_sizeSet = TRUE;
1942
1943 wxSizeEvent event( wxSize(m_width,m_height), GetId() );
1944 event.SetEventObject( this );
1945 GetEventHandler()->ProcessEvent( event );
1946
1947 m_resizing = FALSE;
1948 }
1949
1950 void wxWindow::OnInternalIdle()
1951 {
1952 UpdateWindowUI();
1953 }
1954
1955 void wxWindow::GetSize( int *width, int *height ) const
1956 {
1957 wxCHECK_RET( (m_widget != NULL), _T("invalid window") );
1958
1959 if (width) (*width) = m_width;
1960 if (height) (*height) = m_height;
1961 }
1962
1963 void wxWindow::DoSetClientSize( int width, int height )
1964 {
1965 wxCHECK_RET( (m_widget != NULL), _T("invalid window") );
1966
1967 if (!m_wxwindow)
1968 {
1969 SetSize( width, height );
1970 }
1971 else
1972 {
1973 int dw = 0;
1974 int dh = 0;
1975
1976 if (!m_hasScrolling)
1977 {
1978 GtkStyleClass *window_class = m_wxwindow->style->klass;
1979
1980 if ((m_windowStyle & wxRAISED_BORDER) ||
1981 (m_windowStyle & wxSUNKEN_BORDER))
1982 {
1983 dw += 2 * window_class->xthickness;
1984 dh += 2 * window_class->ythickness;
1985 }
1986 }
1987 else
1988 {
1989 GtkScrolledWindow *scroll_window = GTK_SCROLLED_WINDOW(m_widget);
1990 GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT(m_widget)->klass );
1991
1992 #if (GTK_MINOR_VERSION == 0)
1993 GtkWidget *viewport = scroll_window->viewport;
1994 GtkStyleClass *viewport_class = viewport->style->klass;
1995
1996 if ((m_windowStyle & wxRAISED_BORDER) ||
1997 (m_windowStyle & wxSUNKEN_BORDER))
1998 {
1999 dw += 2 * viewport_class->xthickness;
2000 dh += 2 * viewport_class->ythickness;
2001 }
2002 #endif
2003
2004 /*
2005 GtkWidget *hscrollbar = scroll_window->hscrollbar;
2006 GtkWidget *vscrollbar = scroll_window->vscrollbar;
2007
2008 we use this instead: range.slider_width = 11 + 2*2pts edge
2009 */
2010
2011 if (scroll_window->vscrollbar_visible)
2012 {
2013 dw += 15; /* dw += vscrollbar->allocation.width; */
2014 dw += scroll_class->scrollbar_spacing;
2015 }
2016
2017 if (scroll_window->hscrollbar_visible)
2018 {
2019 dh += 15; /* dh += hscrollbar->allocation.height; */
2020 dw += scroll_class->scrollbar_spacing;
2021 }
2022 }
2023
2024 SetSize( width+dw, height+dh );
2025 }
2026 }
2027
2028 void wxWindow::GetClientSize( int *width, int *height ) const
2029 {
2030 wxCHECK_RET( (m_widget != NULL), _T("invalid window") );
2031
2032 if (!m_wxwindow)
2033 {
2034 if (width) (*width) = m_width;
2035 if (height) (*height) = m_height;
2036 }
2037 else
2038 {
2039 int dw = 0;
2040 int dh = 0;
2041
2042 if (!m_hasScrolling)
2043 {
2044 GtkStyleClass *window_class = m_wxwindow->style->klass;
2045
2046 if ((m_windowStyle & wxRAISED_BORDER) ||
2047 (m_windowStyle & wxSUNKEN_BORDER))
2048 {
2049 dw += 2 * window_class->xthickness;
2050 dh += 2 * window_class->ythickness;
2051 }
2052 }
2053 else
2054 {
2055 GtkScrolledWindow *scroll_window = GTK_SCROLLED_WINDOW(m_widget);
2056 GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT(m_widget)->klass );
2057
2058 #if (GTK_MINOR_VERSION == 0)
2059 GtkWidget *viewport = scroll_window->viewport;
2060 GtkStyleClass *viewport_class = viewport->style->klass;
2061
2062 if ((m_windowStyle & wxRAISED_BORDER) ||
2063 (m_windowStyle & wxSUNKEN_BORDER))
2064 {
2065 dw += 2 * viewport_class->xthickness;
2066 dh += 2 * viewport_class->ythickness;
2067 }
2068 #endif
2069 /*
2070 GtkWidget *hscrollbar = scroll_window->hscrollbar;
2071 GtkWidget *vscrollbar = scroll_window->vscrollbar;
2072
2073 we use this instead: range.slider_width = 11 + 2*2pts edge
2074 */
2075
2076 if (scroll_window->vscrollbar_visible)
2077 {
2078 dw += 15; /* dw += vscrollbar->allocation.width; */
2079 dw += scroll_class->scrollbar_spacing;
2080 }
2081
2082 if (scroll_window->hscrollbar_visible)
2083 {
2084 dh += 15; /* dh += hscrollbar->allocation.height; */
2085 dh += scroll_class->scrollbar_spacing;
2086 }
2087 }
2088
2089 if (width) (*width) = m_width - dw;
2090 if (height) (*height) = m_height - dh;
2091 }
2092 }
2093
2094 void wxWindow::GetPosition( int *x, int *y ) const
2095 {
2096 wxCHECK_RET( (m_widget != NULL), _T("invalid window") );
2097
2098 if (x) (*x) = m_x;
2099 if (y) (*y) = m_y;
2100 }
2101
2102 void wxWindow::ClientToScreen( int *x, int *y )
2103 {
2104 wxCHECK_RET( (m_widget != NULL), _T("invalid window") );
2105
2106 if (!m_widget->window) return;
2107
2108 GdkWindow *source = (GdkWindow *) NULL;
2109 if (m_wxwindow)
2110 source = m_wxwindow->window;
2111 else
2112 source = m_widget->window;
2113
2114 int org_x = 0;
2115 int org_y = 0;
2116 gdk_window_get_origin( source, &org_x, &org_y );
2117
2118 if (!m_wxwindow)
2119 {
2120 if (GTK_WIDGET_NO_WINDOW (m_widget))
2121 {
2122 org_x += m_widget->allocation.x;
2123 org_y += m_widget->allocation.y;
2124 }
2125 }
2126
2127 if (x) *x += org_x;
2128 if (y) *y += org_y;
2129 }
2130
2131 void wxWindow::ScreenToClient( int *x, int *y )
2132 {
2133 wxCHECK_RET( (m_widget != NULL), _T("invalid window") );
2134
2135 if (!m_widget->window) return;
2136
2137 GdkWindow *source = (GdkWindow *) NULL;
2138 if (m_wxwindow)
2139 source = m_wxwindow->window;
2140 else
2141 source = m_widget->window;
2142
2143 int org_x = 0;
2144 int org_y = 0;
2145 gdk_window_get_origin( source, &org_x, &org_y );
2146
2147 if (!m_wxwindow)
2148 {
2149 if (GTK_WIDGET_NO_WINDOW (m_widget))
2150 {
2151 org_x += m_widget->allocation.x;
2152 org_y += m_widget->allocation.y;
2153 }
2154 }
2155
2156 if (x) *x -= org_x;
2157 if (y) *y -= org_y;
2158 }
2159
2160 void wxWindow::Centre( int direction )
2161 {
2162 wxCHECK_RET( (m_widget != NULL), _T("invalid window") );
2163
2164 int x = m_x;
2165 int y = m_y;
2166
2167 if (m_parent)
2168 {
2169 int p_w = 0;
2170 int p_h = 0;
2171 m_parent->GetSize( &p_w, &p_h );
2172 if (direction & wxHORIZONTAL == wxHORIZONTAL) x = (p_w - m_width) / 2;
2173 if (direction & wxVERTICAL == wxVERTICAL) y = (p_h - m_height) / 2;
2174 }
2175 else
2176 {
2177 if (direction & wxHORIZONTAL == wxHORIZONTAL) x = (gdk_screen_width () - m_width) / 2;
2178 if (direction & wxVERTICAL == wxVERTICAL) y = (gdk_screen_height () - m_height) / 2;
2179 }
2180
2181 Move( x, y );
2182 }
2183
2184 void wxWindow::Fit()
2185 {
2186 wxCHECK_RET( (m_widget != NULL), _T("invalid window") );
2187
2188 int maxX = 0;
2189 int maxY = 0;
2190 wxNode *node = m_children.First();
2191 while (node)
2192 {
2193 wxWindow *win = (wxWindow *)node->Data();
2194 int wx, wy, ww, wh;
2195 win->GetPosition(&wx, &wy);
2196 win->GetSize(&ww, &wh);
2197 if (wx + ww > maxX) maxX = wx + ww;
2198 if (wy + wh > maxY) maxY = wy + wh;
2199
2200 node = node->Next();
2201 }
2202
2203 SetClientSize(maxX + 7, maxY + 14);
2204 }
2205
2206 void wxWindow::SetSizeHints( int minW, int minH, int maxW, int maxH, int WXUNUSED(incW), int WXUNUSED(incH) )
2207 {
2208 wxCHECK_RET( (m_widget != NULL), _T("invalid window") );
2209
2210 m_minWidth = minW;
2211 m_minHeight = minH;
2212 m_maxWidth = maxW;
2213 m_maxHeight = maxH;
2214 }
2215
2216 void wxWindow::OnSize( wxSizeEvent &WXUNUSED(event) )
2217 {
2218 // if (GetAutoLayout()) Layout();
2219 }
2220
2221 bool wxWindow::Show( bool show )
2222 {
2223 wxCHECK_MSG( (m_widget != NULL), FALSE, _T("invalid window") );
2224
2225 if (show == m_isShown) return TRUE;
2226
2227 if (show)
2228 gtk_widget_show( m_widget );
2229 else
2230 gtk_widget_hide( m_widget );
2231
2232 m_isShown = show;
2233
2234 return TRUE;
2235 }
2236
2237 void wxWindow::Enable( bool enable )
2238 {
2239 wxCHECK_RET( (m_widget != NULL), _T("invalid window") );
2240
2241 m_isEnabled = enable;
2242
2243 gtk_widget_set_sensitive( m_widget, enable );
2244 if (m_wxwindow) gtk_widget_set_sensitive( m_wxwindow, enable );
2245 }
2246
2247 int wxWindow::GetCharHeight() const
2248 {
2249 wxCHECK_MSG( (m_widget != NULL), 12, _T("invalid window") );
2250
2251 wxCHECK_MSG( m_font.Ok(), 12, _T("invalid font") );
2252
2253 GdkFont *font = m_font.GetInternalFont( 1.0 );
2254
2255 return font->ascent + font->descent;
2256 }
2257
2258 int wxWindow::GetCharWidth() const
2259 {
2260 wxCHECK_MSG( (m_widget != NULL), 8, _T("invalid window") );
2261
2262 wxCHECK_MSG( m_font.Ok(), 8, _T("invalid font") );
2263
2264 GdkFont *font = m_font.GetInternalFont( 1.0 );
2265
2266 return gdk_string_width( font, "H" );
2267 }
2268
2269 void wxWindow::GetTextExtent( const wxString& string, int *x, int *y,
2270 int *descent, int *externalLeading, const wxFont *theFont, bool WXUNUSED(use16) ) const
2271 {
2272 wxFont fontToUse = m_font;
2273 if (theFont) fontToUse = *theFont;
2274
2275 wxCHECK_RET( fontToUse.Ok(), _T("invalid font") );
2276
2277 GdkFont *font = fontToUse.GetInternalFont( 1.0 );
2278 if (x) (*x) = gdk_string_width( font, string.mbc_str() );
2279 if (y) (*y) = font->ascent + font->descent;
2280 if (descent) (*descent) = font->descent;
2281 if (externalLeading) (*externalLeading) = 0; // ??
2282 }
2283
2284 void wxWindow::MakeModal( bool modal )
2285 {
2286 return;
2287
2288 // Disable all other windows
2289 if (this->IsKindOf(CLASSINFO(wxDialog)) || this->IsKindOf(CLASSINFO(wxFrame)))
2290 {
2291 wxNode *node = wxTopLevelWindows.First();
2292 while (node)
2293 {
2294 wxWindow *win = (wxWindow *)node->Data();
2295 if (win != this) win->Enable(!modal);
2296
2297 node = node->Next();
2298 }
2299 }
2300 }
2301
2302 void wxWindow::OnKeyDown( wxKeyEvent &event )
2303 {
2304 event.SetEventType( wxEVT_CHAR );
2305
2306 if (!GetEventHandler()->ProcessEvent( event ))
2307 {
2308 event.Skip();
2309 }
2310 }
2311
2312 void wxWindow::SetFocus()
2313 {
2314 wxCHECK_RET( (m_widget != NULL), _T("invalid window") );
2315
2316 GtkWidget *connect_widget = GetConnectWidget();
2317 if (connect_widget)
2318 {
2319 if (GTK_WIDGET_CAN_FOCUS(connect_widget) /*&& !GTK_WIDGET_HAS_FOCUS (connect_widget)*/ )
2320 {
2321 gtk_widget_grab_focus (connect_widget);
2322 }
2323 else if (GTK_IS_CONTAINER(connect_widget))
2324 {
2325 gtk_container_focus( GTK_CONTAINER(connect_widget), GTK_DIR_TAB_FORWARD );
2326 }
2327 else
2328 {
2329 }
2330 }
2331 }
2332
2333 wxWindow *wxWindow::FindFocus()
2334 {
2335 return g_focusWindow;
2336 }
2337
2338 bool wxWindow::AcceptsFocus() const
2339 {
2340 return IsEnabled() && IsShown() && m_acceptsFocus;
2341 }
2342
2343 void wxWindow::AddChild( wxWindow *child )
2344 {
2345 wxCHECK_RET( (m_widget != NULL), _T("invalid window") );
2346 wxCHECK_RET( (child != NULL), _T("invalid child") );
2347
2348 m_children.Append( child );
2349 }
2350
2351 wxWindow *wxWindow::ReParent( wxWindow *newParent )
2352 {
2353 wxCHECK_MSG( (m_widget != NULL), (wxWindow*) NULL, _T("invalid window") );
2354
2355 wxWindow *oldParent = GetParent();
2356
2357 if (oldParent) oldParent->RemoveChild( this );
2358
2359 gtk_widget_unparent( m_widget );
2360
2361 if (newParent)
2362 {
2363 newParent->AddChild( this );
2364 (newParent->m_insertCallback)( newParent, this );
2365 }
2366
2367 return oldParent;
2368 }
2369
2370 void wxWindow::RemoveChild( wxWindow *child )
2371 {
2372 m_children.DeleteObject( child );
2373 child->m_parent = (wxWindow *) NULL;
2374 }
2375
2376 void wxWindow::SetReturnCode( int retCode )
2377 {
2378 m_retCode = retCode;
2379 }
2380
2381 int wxWindow::GetReturnCode()
2382 {
2383 return m_retCode;
2384 }
2385
2386 void wxWindow::Raise()
2387 {
2388 wxCHECK_RET( (m_widget != NULL), _T("invalid window") );
2389
2390 if (!m_widget->window) return;
2391
2392 if (m_widget) gdk_window_raise( m_widget->window );
2393 }
2394
2395 void wxWindow::Lower()
2396 {
2397 wxCHECK_RET( (m_widget != NULL), _T("invalid window") );
2398
2399 if (!m_widget->window) return;
2400
2401 if (m_widget) gdk_window_lower( m_widget->window );
2402 }
2403
2404 wxEvtHandler *wxWindow::GetEventHandler() const
2405 {
2406 return m_eventHandler;
2407 }
2408
2409 void wxWindow::SetEventHandler( wxEvtHandler *handler )
2410 {
2411 m_eventHandler = handler;
2412 }
2413
2414 void wxWindow::PushEventHandler(wxEvtHandler *handler)
2415 {
2416 handler->SetNextHandler(GetEventHandler());
2417 SetEventHandler(handler);
2418 }
2419
2420 wxEvtHandler *wxWindow::PopEventHandler(bool deleteHandler)
2421 {
2422 if (GetEventHandler())
2423 {
2424 wxEvtHandler *handlerA = GetEventHandler();
2425 wxEvtHandler *handlerB = handlerA->GetNextHandler();
2426 handlerA->SetNextHandler((wxEvtHandler *) NULL);
2427 SetEventHandler(handlerB);
2428 if (deleteHandler)
2429 {
2430 delete handlerA;
2431 return (wxEvtHandler*) NULL;
2432 }
2433 else
2434 return handlerA;
2435 }
2436 else
2437 return (wxEvtHandler *) NULL;
2438 }
2439
2440 wxValidator *wxWindow::GetValidator()
2441 {
2442 return m_windowValidator;
2443 }
2444
2445 void wxWindow::SetValidator( const wxValidator& validator )
2446 {
2447 if (m_windowValidator) delete m_windowValidator;
2448 m_windowValidator = validator.Clone();
2449 if (m_windowValidator) m_windowValidator->SetWindow(this);
2450 }
2451
2452 void wxWindow::SetClientObject( wxClientData *data )
2453 {
2454 if (m_clientObject) delete m_clientObject;
2455 m_clientObject = data;
2456 }
2457
2458 wxClientData *wxWindow::GetClientObject()
2459 {
2460 return m_clientObject;
2461 }
2462
2463 void wxWindow::SetClientData( void *data )
2464 {
2465 m_clientData = data;
2466 }
2467
2468 void *wxWindow::GetClientData()
2469 {
2470 return m_clientData;
2471 }
2472
2473 bool wxWindow::IsBeingDeleted()
2474 {
2475 return FALSE;
2476 }
2477
2478 void wxWindow::SetId( wxWindowID id )
2479 {
2480 m_windowId = id;
2481 }
2482
2483 wxWindowID wxWindow::GetId() const
2484 {
2485 return m_windowId;
2486 }
2487
2488 void wxWindow::SetCursor( const wxCursor &cursor )
2489 {
2490 wxCHECK_RET( (m_widget != NULL), _T("invalid window") );
2491
2492 if (cursor.Ok())
2493 {
2494 if (cursor == *m_cursor) return;
2495 *m_cursor = cursor;
2496 }
2497 else
2498 {
2499 *m_cursor = *wxSTANDARD_CURSOR;
2500 }
2501
2502 if (!m_widget->window) return;
2503
2504 gdk_window_set_cursor( m_widget->window, m_cursor->GetCursor() );
2505
2506 if ((m_wxwindow) && (m_wxwindow->window))
2507 gdk_window_set_cursor( m_wxwindow->window, m_cursor->GetCursor() );
2508 }
2509
2510 void wxWindow::WarpPointer( int WXUNUSED(x), int WXUNUSED(y) )
2511 {
2512 // TODO
2513 }
2514
2515 void wxWindow::Refresh( bool eraseBackground, const wxRect *rect )
2516 {
2517 wxCHECK_RET( (m_widget != NULL), _T("invalid window") );
2518
2519 if (!m_widget->window) return;
2520
2521 if (eraseBackground && m_wxwindow && m_wxwindow->window)
2522 {
2523 if (rect)
2524 {
2525 gdk_window_clear_area( m_wxwindow->window,
2526 rect->x, rect->y,
2527 rect->width, rect->height );
2528 }
2529 else
2530 {
2531 gdk_window_clear( m_wxwindow->window );
2532 }
2533 }
2534
2535 if (!rect)
2536 {
2537 if (m_wxwindow)
2538 gtk_widget_draw( m_wxwindow, (GdkRectangle*) NULL );
2539 else
2540 gtk_widget_draw( m_widget, (GdkRectangle*) NULL );
2541 }
2542 else
2543 {
2544 GdkRectangle gdk_rect;
2545 gdk_rect.x = rect->x;
2546 gdk_rect.y = rect->y;
2547 gdk_rect.width = rect->width;
2548 gdk_rect.height = rect->height;
2549
2550 if (m_wxwindow)
2551 gtk_widget_draw( m_wxwindow, &gdk_rect );
2552 else
2553 gtk_widget_draw( m_widget, &gdk_rect );
2554 }
2555 }
2556
2557 wxRegion wxWindow::GetUpdateRegion() const
2558 {
2559 return m_updateRegion;
2560 }
2561
2562 bool wxWindow::IsExposed( int x, int y) const
2563 {
2564 return (m_updateRegion.Contains( x, y ) != wxOutRegion );
2565 }
2566
2567 bool wxWindow::IsExposed( int x, int y, int w, int h ) const
2568 {
2569 return (m_updateRegion.Contains( x, y, w, h ) != wxOutRegion );
2570 }
2571
2572 bool wxWindow::IsExposed( const wxPoint& pt ) const
2573 {
2574 return (m_updateRegion.Contains( pt.x, pt.y ) != wxOutRegion );
2575 }
2576
2577 bool wxWindow::IsExposed( const wxRect& rect ) const
2578 {
2579 return (m_updateRegion.Contains( rect.x, rect.y, rect.width, rect.height ) != wxOutRegion );
2580 }
2581
2582 void wxWindow::Clear()
2583 {
2584 wxCHECK_RET( m_widget != NULL, _T("invalid window") );
2585
2586 if (!m_widget->window) return;
2587
2588 if (m_wxwindow && m_wxwindow->window)
2589 {
2590 gdk_window_clear( m_wxwindow->window );
2591 }
2592 }
2593
2594 #if wxUSE_TOOLTIPS
2595 void wxWindow::SetToolTip( const wxString &tip )
2596 {
2597 if (m_toolTip)
2598 {
2599 m_toolTip->SetTip( tip );
2600 }
2601 else
2602 {
2603 SetToolTip( new wxToolTip( tip ) );
2604 }
2605
2606 // setting empty tooltip text does not remove the tooltip any more for
2607 // wxMSW compatibility - use SetToolTip((wxToolTip *)NULL) for this
2608 }
2609
2610 void wxWindow::SetToolTip( wxToolTip *tip )
2611 {
2612 if (m_toolTip)
2613 {
2614 m_toolTip->SetTip( (char*) NULL );
2615 delete m_toolTip;
2616 }
2617
2618 m_toolTip = tip;
2619
2620 if (m_toolTip)
2621 m_toolTip->Apply( this );
2622 }
2623
2624 void wxWindow::ApplyToolTip( GtkTooltips *tips, const wxChar *tip )
2625 {
2626 gtk_tooltips_set_tip( tips, GetConnectWidget(), wxConv_current->cWX2MB(tip), (gchar*) NULL );
2627 }
2628 #endif // wxUSE_TOOLTIPS
2629
2630 wxColour wxWindow::GetBackgroundColour() const
2631 {
2632 return m_backgroundColour;
2633 }
2634
2635 void wxWindow::SetBackgroundColour( const wxColour &colour )
2636 {
2637 wxCHECK_RET( m_widget != NULL, _T("invalid window") );
2638
2639 if (m_backgroundColour == colour) return;
2640
2641 m_backgroundColour = colour;
2642 if (!m_backgroundColour.Ok()) return;
2643
2644 if (!m_widget->window) return;
2645
2646 if (m_wxwindow && m_wxwindow->window)
2647 {
2648 /* wxMSW doesn't clear the window here. I don't do that
2649 either to provide compatibility. call Clear() to do
2650 the job. */
2651
2652 m_backgroundColour.CalcPixel( gdk_window_get_colormap( m_wxwindow->window ) );
2653 gdk_window_set_background( m_wxwindow->window, m_backgroundColour.GetColor() );
2654 }
2655
2656 wxColour sysbg = wxSystemSettings::GetSystemColour( wxSYS_COLOUR_BTNFACE );
2657
2658 if (sysbg.Red() == colour.Red() &&
2659 sysbg.Green() == colour.Green() &&
2660 sysbg.Blue() == colour.Blue())
2661 {
2662 m_backgroundColour = wxNullColour;
2663 ApplyWidgetStyle();
2664 m_backgroundColour = sysbg;
2665 }
2666 else
2667 {
2668 ApplyWidgetStyle();
2669 }
2670 }
2671
2672 wxColour wxWindow::GetForegroundColour() const
2673 {
2674 return m_foregroundColour;
2675 }
2676
2677 void wxWindow::SetForegroundColour( const wxColour &colour )
2678 {
2679 wxCHECK_RET( m_widget != NULL, _T("invalid window") );
2680
2681 if (m_foregroundColour == colour) return;
2682
2683 m_foregroundColour = colour;
2684 if (!m_foregroundColour.Ok()) return;
2685
2686 if (!m_widget->window) return;
2687
2688 wxColour sysbg = wxSystemSettings::GetSystemColour( wxSYS_COLOUR_BTNFACE );
2689 if (sysbg.Red() == colour.Red() &&
2690 sysbg.Green() == colour.Green() &&
2691 sysbg.Blue() == colour.Blue())
2692 {
2693 m_backgroundColour = wxNullColour;
2694 ApplyWidgetStyle();
2695 m_backgroundColour = sysbg;
2696 }
2697 else
2698 {
2699 ApplyWidgetStyle();
2700 }
2701 }
2702
2703 GtkStyle *wxWindow::GetWidgetStyle()
2704 {
2705 if (m_widgetStyle) gtk_style_unref( m_widgetStyle );
2706
2707 m_widgetStyle =
2708 gtk_style_copy(
2709 gtk_widget_get_style( m_widget ) );
2710
2711 return m_widgetStyle;
2712 }
2713
2714 void wxWindow::SetWidgetStyle()
2715 {
2716 GtkStyle *style = GetWidgetStyle();
2717
2718 gdk_font_unref( style->font );
2719 style->font = gdk_font_ref( m_font.GetInternalFont( 1.0 ) );
2720
2721 if (m_foregroundColour.Ok())
2722 {
2723 m_foregroundColour.CalcPixel( gdk_window_get_colormap( m_widget->window ) );
2724 style->fg[GTK_STATE_NORMAL] = *m_foregroundColour.GetColor();
2725 style->fg[GTK_STATE_PRELIGHT] = *m_foregroundColour.GetColor();
2726 style->fg[GTK_STATE_ACTIVE] = *m_foregroundColour.GetColor();
2727 }
2728
2729 if (m_backgroundColour.Ok())
2730 {
2731 m_backgroundColour.CalcPixel( gdk_window_get_colormap( m_widget->window ) );
2732 style->bg[GTK_STATE_NORMAL] = *m_backgroundColour.GetColor();
2733 style->base[GTK_STATE_NORMAL] = *m_backgroundColour.GetColor();
2734 style->bg[GTK_STATE_PRELIGHT] = *m_backgroundColour.GetColor();
2735 style->base[GTK_STATE_PRELIGHT] = *m_backgroundColour.GetColor();
2736 style->bg[GTK_STATE_ACTIVE] = *m_backgroundColour.GetColor();
2737 style->base[GTK_STATE_ACTIVE] = *m_backgroundColour.GetColor();
2738 style->bg[GTK_STATE_INSENSITIVE] = *m_backgroundColour.GetColor();
2739 style->base[GTK_STATE_INSENSITIVE] = *m_backgroundColour.GetColor();
2740 }
2741 }
2742
2743 void wxWindow::ApplyWidgetStyle()
2744 {
2745 }
2746
2747 bool wxWindow::Validate()
2748 {
2749 wxCHECK_MSG( m_widget != NULL, FALSE, _T("invalid window") );
2750
2751 wxNode *node = m_children.First();
2752 while (node)
2753 {
2754 wxWindow *child = (wxWindow *)node->Data();
2755 if (child->GetValidator() && /* child->GetValidator()->Ok() && */ !child->GetValidator()->Validate(this))
2756 {
2757 return FALSE;
2758 }
2759 node = node->Next();
2760 }
2761 return TRUE;
2762 }
2763
2764 bool wxWindow::TransferDataToWindow()
2765 {
2766 wxCHECK_MSG( m_widget != NULL, FALSE, _T("invalid window") );
2767
2768 wxNode *node = m_children.First();
2769 while (node)
2770 {
2771 wxWindow *child = (wxWindow *)node->Data();
2772 if (child->GetValidator() && /* child->GetValidator()->Ok() && */
2773 !child->GetValidator()->TransferToWindow() )
2774 {
2775 wxMessageBox( _("Application Error"), _("Could not transfer data to window"), wxOK|wxICON_EXCLAMATION );
2776 return FALSE;
2777 }
2778 node = node->Next();
2779 }
2780 return TRUE;
2781 }
2782
2783 bool wxWindow::TransferDataFromWindow()
2784 {
2785 wxCHECK_MSG( m_widget != NULL, FALSE, _T("invalid window") );
2786
2787 wxNode *node = m_children.First();
2788 while (node)
2789 {
2790 wxWindow *child = (wxWindow *)node->Data();
2791 if ( child->GetValidator() && /* child->GetValidator()->Ok() && */ !child->GetValidator()->TransferFromWindow() )
2792 {
2793 return FALSE;
2794 }
2795 node = node->Next();
2796 }
2797 return TRUE;
2798 }
2799
2800 void wxWindow::SetAcceleratorTable( const wxAcceleratorTable& accel )
2801 {
2802 m_acceleratorTable = accel;
2803 }
2804
2805 void wxWindow::OnInitDialog( wxInitDialogEvent &WXUNUSED(event) )
2806 {
2807 TransferDataToWindow();
2808 }
2809
2810 void wxWindow::InitDialog()
2811 {
2812 wxCHECK_RET( m_widget != NULL, _T("invalid window") );
2813
2814 wxInitDialogEvent event(GetId());
2815 event.SetEventObject( this );
2816 GetEventHandler()->ProcessEvent(event);
2817 }
2818
2819 static void SetInvokingWindow( wxMenu *menu, wxWindow *win )
2820 {
2821 menu->SetInvokingWindow( win );
2822 wxNode *node = menu->GetItems().First();
2823 while (node)
2824 {
2825 wxMenuItem *menuitem = (wxMenuItem*)node->Data();
2826 if (menuitem->IsSubMenu())
2827 {
2828 SetInvokingWindow( menuitem->GetSubMenu(), win );
2829 }
2830 node = node->Next();
2831 }
2832 }
2833
2834 static gint gs_pop_x = 0;
2835 static gint gs_pop_y = 0;
2836
2837 static void pop_pos_callback( GtkMenu *menu, gint *x, gint *y, wxWindow *win )
2838 {
2839 win->ClientToScreen( &gs_pop_x, &gs_pop_y );
2840 *x = gs_pop_x;
2841 *y = gs_pop_y;
2842 }
2843
2844 bool wxWindow::PopupMenu( wxMenu *menu, int x, int y )
2845 {
2846 wxCHECK_MSG( m_widget != NULL, FALSE, _T("invalid window") );
2847
2848 wxCHECK_MSG( menu != NULL, FALSE, _T("invalid popup-menu") );
2849
2850 SetInvokingWindow( menu, this );
2851
2852 menu->UpdateUI();
2853
2854 gs_pop_x = x;
2855 gs_pop_y = y;
2856
2857 gtk_menu_popup(
2858 GTK_MENU(menu->m_menu),
2859 (GtkWidget *) NULL, // parent menu shell
2860 (GtkWidget *) NULL, // parent menu item
2861 (GtkMenuPositionFunc) pop_pos_callback,
2862 (gpointer) this, // client data
2863 0, // button used to activate it
2864 0 //gs_timeLastClick // the time of activation
2865 );
2866 return TRUE;
2867 }
2868
2869 #if wxUSE_DRAG_AND_DROP
2870
2871 void wxWindow::SetDropTarget( wxDropTarget *dropTarget )
2872 {
2873 wxCHECK_RET( m_widget != NULL, _T("invalid window") );
2874
2875 GtkWidget *dnd_widget = GetConnectWidget();
2876
2877 if (m_dropTarget) m_dropTarget->UnregisterWidget( dnd_widget );
2878
2879 if (m_dropTarget) delete m_dropTarget;
2880 m_dropTarget = dropTarget;
2881
2882 if (m_dropTarget) m_dropTarget->RegisterWidget( dnd_widget );
2883 }
2884
2885 wxDropTarget *wxWindow::GetDropTarget() const
2886 {
2887 return m_dropTarget;
2888 }
2889
2890 #endif
2891
2892 GtkWidget* wxWindow::GetConnectWidget()
2893 {
2894 GtkWidget *connect_widget = m_widget;
2895 if (m_wxwindow) connect_widget = m_wxwindow;
2896
2897 return connect_widget;
2898 }
2899
2900 bool wxWindow::IsOwnGtkWindow( GdkWindow *window )
2901 {
2902 if (m_wxwindow) return (window == m_wxwindow->window);
2903 return (window == m_widget->window);
2904 }
2905
2906 void wxWindow::SetFont( const wxFont &font )
2907 {
2908 wxCHECK_RET( m_widget != NULL, _T("invalid window") );
2909
2910 if (m_font == font) return;
2911
2912 if (((wxFont*)&font)->Ok())
2913 m_font = font;
2914 else
2915 m_font = *wxSWISS_FONT;
2916
2917 wxColour sysbg = wxSystemSettings::GetSystemColour( wxSYS_COLOUR_BTNFACE );
2918 if (sysbg.Red() == m_backgroundColour.Red() &&
2919 sysbg.Green() == m_backgroundColour.Green() &&
2920 sysbg.Blue() == m_backgroundColour.Blue())
2921 {
2922 m_backgroundColour = wxNullColour;
2923 ApplyWidgetStyle();
2924 m_backgroundColour = sysbg;
2925 }
2926 else
2927 {
2928 ApplyWidgetStyle();
2929 }
2930 }
2931
2932 void wxWindow::SetWindowStyleFlag( long flag )
2933 {
2934 m_windowStyle = flag;
2935 }
2936
2937 long wxWindow::GetWindowStyleFlag() const
2938 {
2939 return m_windowStyle;
2940 }
2941
2942 void wxWindow::CaptureMouse()
2943 {
2944 wxCHECK_RET( m_widget != NULL, _T("invalid window") );
2945
2946 wxCHECK_RET( g_capturing == FALSE, _T("CaptureMouse called twice") );
2947
2948 if (!m_widget->window) return;
2949
2950 GtkWidget *connect_widget = GetConnectWidget();
2951 gtk_grab_add( connect_widget );
2952 gdk_pointer_grab( connect_widget->window, FALSE,
2953 (GdkEventMask)
2954 (GDK_BUTTON_PRESS_MASK |
2955 GDK_BUTTON_RELEASE_MASK |
2956 GDK_POINTER_MOTION_MASK),
2957 (GdkWindow *) NULL,
2958 (GdkCursor *) NULL,
2959 GDK_CURRENT_TIME );
2960 g_capturing = TRUE;
2961 }
2962
2963 void wxWindow::ReleaseMouse()
2964 {
2965 wxCHECK_RET( m_widget != NULL, _T("invalid window") );
2966
2967 wxCHECK_RET( g_capturing == TRUE, _T("ReleaseMouse called twice") );
2968
2969 if (!m_widget->window) return;
2970
2971 GtkWidget *connect_widget = GetConnectWidget();
2972 gtk_grab_remove( connect_widget );
2973 gdk_pointer_ungrab ( GDK_CURRENT_TIME );
2974 g_capturing = FALSE;
2975 }
2976
2977 void wxWindow::SetTitle( const wxString &WXUNUSED(title) )
2978 {
2979 }
2980
2981 wxString wxWindow::GetTitle() const
2982 {
2983 return (wxString&)m_windowName;
2984 }
2985
2986 wxString wxWindow::GetLabel() const
2987 {
2988 return GetTitle();
2989 }
2990
2991 void wxWindow::SetName( const wxString &name )
2992 {
2993 m_windowName = name;
2994 }
2995
2996 wxString wxWindow::GetName() const
2997 {
2998 return (wxString&)m_windowName;
2999 }
3000
3001 bool wxWindow::IsShown() const
3002 {
3003 return m_isShown;
3004 }
3005
3006 bool wxWindow::IsRetained()
3007 {
3008 return FALSE;
3009 }
3010
3011 wxWindow *wxWindow::FindWindow( long id )
3012 {
3013 if (id == m_windowId) return this;
3014 wxNode *node = m_children.First();
3015 while (node)
3016 {
3017 wxWindow *child = (wxWindow*)node->Data();
3018 wxWindow *res = child->FindWindow( id );
3019 if (res) return res;
3020 node = node->Next();
3021 }
3022 return (wxWindow *) NULL;
3023 }
3024
3025 wxWindow *wxWindow::FindWindow( const wxString& name )
3026 {
3027 if (name == m_windowName) return this;
3028 wxNode *node = m_children.First();
3029 while (node)
3030 {
3031 wxWindow *child = (wxWindow*)node->Data();
3032 wxWindow *res = child->FindWindow( name );
3033 if (res) return res;
3034 node = node->Next();
3035 }
3036 return (wxWindow *) NULL;
3037 }
3038
3039 void wxWindow::SetScrollbar( int orient, int pos, int thumbVisible,
3040 int range, bool refresh )
3041 {
3042 wxCHECK_RET( m_widget != NULL, _T("invalid window") );
3043
3044 wxCHECK_RET( m_wxwindow != NULL, _T("window needs client area for scrolling") );
3045
3046 m_hasScrolling = TRUE;
3047
3048 if (orient == wxHORIZONTAL)
3049 {
3050 float fpos = (float)pos;
3051 float frange = (float)range;
3052 float fthumb = (float)thumbVisible;
3053 if (fpos > frange-fthumb) fpos = frange-fthumb;
3054 if (fpos < 0.0) fpos = 0.0;
3055
3056 if ((fabs(frange-m_hAdjust->upper) < 0.2) &&
3057 (fabs(fthumb-m_hAdjust->page_size) < 0.2))
3058 {
3059 SetScrollPos( orient, pos, refresh );
3060 return;
3061 }
3062
3063 m_oldHorizontalPos = fpos;
3064
3065 m_hAdjust->lower = 0.0;
3066 m_hAdjust->upper = frange;
3067 m_hAdjust->value = fpos;
3068 m_hAdjust->step_increment = 1.0;
3069 m_hAdjust->page_increment = (float)(wxMax(fthumb,0));
3070 m_hAdjust->page_size = fthumb;
3071 }
3072 else
3073 {
3074 float fpos = (float)pos;
3075 float frange = (float)range;
3076 float fthumb = (float)thumbVisible;
3077 if (fpos > frange-fthumb) fpos = frange-fthumb;
3078 if (fpos < 0.0) fpos = 0.0;
3079
3080 if ((fabs(frange-m_vAdjust->upper) < 0.2) &&
3081 (fabs(fthumb-m_vAdjust->page_size) < 0.2))
3082 {
3083 SetScrollPos( orient, pos, refresh );
3084 return;
3085 }
3086
3087 m_oldVerticalPos = fpos;
3088
3089 m_vAdjust->lower = 0.0;
3090 m_vAdjust->upper = frange;
3091 m_vAdjust->value = fpos;
3092 m_vAdjust->step_increment = 1.0;
3093 m_vAdjust->page_increment = (float)(wxMax(fthumb,0));
3094 m_vAdjust->page_size = fthumb;
3095 }
3096
3097 if (m_wxwindow)
3098 {
3099 if (orient == wxHORIZONTAL)
3100 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust), "changed" );
3101 else
3102 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust), "changed" );
3103
3104 gtk_widget_set_usize( m_widget, m_width, m_height );
3105 }
3106 }
3107
3108 void wxWindow::SetScrollPos( int orient, int pos, bool WXUNUSED(refresh) )
3109 {
3110 wxCHECK_RET( m_widget != NULL, _T("invalid window") );
3111
3112 wxCHECK_RET( m_wxwindow != NULL, _T("window needs client area for scrolling") );
3113
3114 if (orient == wxHORIZONTAL)
3115 {
3116 float fpos = (float)pos;
3117 if (fpos > m_hAdjust->upper - m_hAdjust->page_size) fpos = m_hAdjust->upper - m_hAdjust->page_size;
3118 if (fpos < 0.0) fpos = 0.0;
3119 m_oldHorizontalPos = fpos;
3120
3121 if (fabs(fpos-m_hAdjust->value) < 0.2) return;
3122 m_hAdjust->value = fpos;
3123 }
3124 else
3125 {
3126 float fpos = (float)pos;
3127 if (fpos > m_vAdjust->upper - m_vAdjust->page_size) fpos = m_vAdjust->upper - m_vAdjust->page_size;
3128 if (fpos < 0.0) fpos = 0.0;
3129 m_oldVerticalPos = fpos;
3130
3131 if (fabs(fpos-m_vAdjust->value) < 0.2) return;
3132 m_vAdjust->value = fpos;
3133 }
3134
3135 if (!m_isScrolling)
3136 {
3137 if (m_wxwindow->window)
3138 {
3139 if (orient == wxHORIZONTAL)
3140 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust), "value_changed" );
3141 else
3142 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust), "value_changed" );
3143 }
3144 }
3145 }
3146
3147 int wxWindow::GetScrollThumb( int orient ) const
3148 {
3149 wxCHECK_MSG( m_widget != NULL, 0, _T("invalid window") );
3150
3151 wxCHECK_MSG( m_wxwindow != NULL, 0, _T("window needs client area for scrolling") );
3152
3153 if (orient == wxHORIZONTAL)
3154 return (int)(m_hAdjust->page_size+0.5);
3155 else
3156 return (int)(m_vAdjust->page_size+0.5);
3157 }
3158
3159 int wxWindow::GetScrollPos( int orient ) const
3160 {
3161 wxCHECK_MSG( m_widget != NULL, 0, _T("invalid window") );
3162
3163 wxCHECK_MSG( m_wxwindow != NULL, 0, _T("window needs client area for scrolling") );
3164
3165 if (orient == wxHORIZONTAL)
3166 return (int)(m_hAdjust->value+0.5);
3167 else
3168 return (int)(m_vAdjust->value+0.5);
3169 }
3170
3171 int wxWindow::GetScrollRange( int orient ) const
3172 {
3173 wxCHECK_MSG( m_widget != NULL, 0, _T("invalid window") );
3174
3175 wxCHECK_MSG( m_wxwindow != NULL, 0, _T("window needs client area for scrolling") );
3176
3177 if (orient == wxHORIZONTAL)
3178 return (int)(m_hAdjust->upper+0.5);
3179 else
3180 return (int)(m_vAdjust->upper+0.5);
3181 }
3182
3183 void wxWindow::ScrollWindow( int dx, int dy, const wxRect* WXUNUSED(rect) )
3184 {
3185 wxCHECK_RET( m_widget != NULL, _T("invalid window") );
3186
3187 wxCHECK_RET( m_wxwindow != NULL, _T("window needs client area for scrolling") );
3188
3189 wxNode *node = m_children.First();
3190 while (node)
3191 {
3192 wxWindow *child = (wxWindow*) node->Data();
3193 child->Move( child->m_x + dx, child->m_y + dy );
3194 node = node->Next();
3195 }
3196
3197 int cw = 0;
3198 int ch = 0;
3199 GetClientSize( &cw, &ch );
3200
3201 int w = cw - abs(dx);
3202 int h = ch - abs(dy);
3203 if ((h < 0) || (w < 0))
3204 {
3205 Refresh();
3206 return;
3207 }
3208 int s_x = 0;
3209 int s_y = 0;
3210 if (dx < 0) s_x = -dx;
3211 if (dy < 0) s_y = -dy;
3212 int d_x = 0;
3213 int d_y = 0;
3214 if (dx > 0) d_x = dx;
3215 if (dy > 0) d_y = dy;
3216
3217 if (!m_scrollGC)
3218 {
3219 m_scrollGC = gdk_gc_new( m_wxwindow->window );
3220 gdk_gc_set_exposures( m_scrollGC, TRUE );
3221 }
3222
3223 gdk_window_copy_area( m_wxwindow->window, m_scrollGC, d_x, d_y,
3224 m_wxwindow->window, s_x, s_y, w, h );
3225
3226 wxRect rect;
3227 if (dx < 0) rect.x = cw+dx; else rect.x = 0;
3228 if (dy < 0) rect.y = ch+dy; else rect.y = 0;
3229 if (dy != 0) rect.width = cw; else rect.width = abs(dx);
3230 if (dx != 0) rect.height = ch; else rect.height = abs(dy);
3231
3232 Refresh( TRUE, &rect );
3233 }
3234
3235 //-------------------------------------------------------------------------------------
3236 // Layout
3237 //-------------------------------------------------------------------------------------
3238
3239 wxLayoutConstraints *wxWindow::GetConstraints() const
3240 {
3241 return m_constraints;
3242 }
3243
3244 void wxWindow::SetConstraints( wxLayoutConstraints *constraints )
3245 {
3246 if (m_constraints)
3247 {
3248 UnsetConstraints(m_constraints);
3249 delete m_constraints;
3250 }
3251 m_constraints = constraints;
3252 if (m_constraints)
3253 {
3254 // Make sure other windows know they're part of a 'meaningful relationship'
3255 if (m_constraints->left.GetOtherWindow() && (m_constraints->left.GetOtherWindow() != this))
3256 m_constraints->left.GetOtherWindow()->AddConstraintReference((wxWindow *)this);
3257 if (m_constraints->top.GetOtherWindow() && (m_constraints->top.GetOtherWindow() != this))
3258 m_constraints->top.GetOtherWindow()->AddConstraintReference((wxWindow *)this);
3259 if (m_constraints->right.GetOtherWindow() && (m_constraints->right.GetOtherWindow() != this))
3260 m_constraints->right.GetOtherWindow()->AddConstraintReference((wxWindow *)this);
3261 if (m_constraints->bottom.GetOtherWindow() && (m_constraints->bottom.GetOtherWindow() != this))
3262 m_constraints->bottom.GetOtherWindow()->AddConstraintReference((wxWindow *)this);
3263 if (m_constraints->width.GetOtherWindow() && (m_constraints->width.GetOtherWindow() != this))
3264 m_constraints->width.GetOtherWindow()->AddConstraintReference((wxWindow *)this);
3265 if (m_constraints->height.GetOtherWindow() && (m_constraints->height.GetOtherWindow() != this))
3266 m_constraints->height.GetOtherWindow()->AddConstraintReference((wxWindow *)this);
3267 if (m_constraints->centreX.GetOtherWindow() && (m_constraints->centreX.GetOtherWindow() != this))
3268 m_constraints->centreX.GetOtherWindow()->AddConstraintReference((wxWindow *)this);
3269 if (m_constraints->centreY.GetOtherWindow() && (m_constraints->centreY.GetOtherWindow() != this))
3270 m_constraints->centreY.GetOtherWindow()->AddConstraintReference((wxWindow *)this);
3271 }
3272 ;
3273 }
3274 ;
3275
3276 void wxWindow::SetAutoLayout( bool autoLayout )
3277 {
3278 m_autoLayout = autoLayout;
3279 }
3280
3281 bool wxWindow::GetAutoLayout() const
3282 {
3283 return m_autoLayout;
3284 }
3285
3286 wxSizer *wxWindow::GetSizer() const
3287 {
3288 return m_windowSizer;
3289 }
3290
3291 void wxWindow::SetSizerParent( wxWindow *win )
3292 {
3293 m_sizerParent = win;
3294 }
3295
3296 wxWindow *wxWindow::GetSizerParent() const
3297 {
3298 return m_sizerParent;
3299 }
3300
3301 // This removes any dangling pointers to this window
3302 // in other windows' constraintsInvolvedIn lists.
3303 void wxWindow::UnsetConstraints(wxLayoutConstraints *c)
3304 {
3305 if (c)
3306 {
3307 if (c->left.GetOtherWindow() && (c->top.GetOtherWindow() != this))
3308 c->left.GetOtherWindow()->RemoveConstraintReference((wxWindow *)this);
3309 if (c->top.GetOtherWindow() && (c->top.GetOtherWindow() != this))
3310 c->top.GetOtherWindow()->RemoveConstraintReference((wxWindow *)this);
3311 if (c->right.GetOtherWindow() && (c->right.GetOtherWindow() != this))
3312 c->right.GetOtherWindow()->RemoveConstraintReference((wxWindow *)this);
3313 if (c->bottom.GetOtherWindow() && (c->bottom.GetOtherWindow() != this))
3314 c->bottom.GetOtherWindow()->RemoveConstraintReference((wxWindow *)this);
3315 if (c->width.GetOtherWindow() && (c->width.GetOtherWindow() != this))
3316 c->width.GetOtherWindow()->RemoveConstraintReference((wxWindow *)this);
3317 if (c->height.GetOtherWindow() && (c->height.GetOtherWindow() != this))
3318 c->height.GetOtherWindow()->RemoveConstraintReference((wxWindow *)this);
3319 if (c->centreX.GetOtherWindow() && (c->centreX.GetOtherWindow() != this))
3320 c->centreX.GetOtherWindow()->RemoveConstraintReference((wxWindow *)this);
3321 if (c->centreY.GetOtherWindow() && (c->centreY.GetOtherWindow() != this))
3322 c->centreY.GetOtherWindow()->RemoveConstraintReference((wxWindow *)this);
3323 }
3324 }
3325
3326 // Back-pointer to other windows we're involved with, so if we delete
3327 // this window, we must delete any constraints we're involved with.
3328 void wxWindow::AddConstraintReference(wxWindow *otherWin)
3329 {
3330 if (!m_constraintsInvolvedIn)
3331 m_constraintsInvolvedIn = new wxList;
3332 if (!m_constraintsInvolvedIn->Member(otherWin))
3333 m_constraintsInvolvedIn->Append(otherWin);
3334 }
3335
3336 // REMOVE back-pointer to other windows we're involved with.
3337 void wxWindow::RemoveConstraintReference(wxWindow *otherWin)
3338 {
3339 if (m_constraintsInvolvedIn)
3340 m_constraintsInvolvedIn->DeleteObject(otherWin);
3341 }
3342
3343 // Reset any constraints that mention this window
3344 void wxWindow::DeleteRelatedConstraints()
3345 {
3346 if (m_constraintsInvolvedIn)
3347 {
3348 wxNode *node = m_constraintsInvolvedIn->First();
3349 while (node)
3350 {
3351 wxWindow *win = (wxWindow *)node->Data();
3352 wxNode *next = node->Next();
3353 wxLayoutConstraints *constr = win->GetConstraints();
3354
3355 // Reset any constraints involving this window
3356 if (constr)
3357 {
3358 constr->left.ResetIfWin((wxWindow *)this);
3359 constr->top.ResetIfWin((wxWindow *)this);
3360 constr->right.ResetIfWin((wxWindow *)this);
3361 constr->bottom.ResetIfWin((wxWindow *)this);
3362 constr->width.ResetIfWin((wxWindow *)this);
3363 constr->height.ResetIfWin((wxWindow *)this);
3364 constr->centreX.ResetIfWin((wxWindow *)this);
3365 constr->centreY.ResetIfWin((wxWindow *)this);
3366 }
3367 delete node;
3368 node = next;
3369 }
3370 delete m_constraintsInvolvedIn;
3371 m_constraintsInvolvedIn = (wxList *) NULL;
3372 }
3373 }
3374
3375 void wxWindow::SetSizer(wxSizer *sizer)
3376 {
3377 m_windowSizer = sizer;
3378 if (sizer)
3379 sizer->SetSizerParent((wxWindow *)this);
3380 }
3381
3382 /*
3383 * New version
3384 */
3385
3386 bool wxWindow::Layout()
3387 {
3388 if (GetConstraints())
3389 {
3390 int w, h;
3391 GetClientSize(&w, &h);
3392 GetConstraints()->width.SetValue(w);
3393 GetConstraints()->height.SetValue(h);
3394 }
3395
3396 // If top level (one sizer), evaluate the sizer's constraints.
3397 if (GetSizer())
3398 {
3399 int noChanges;
3400 GetSizer()->ResetConstraints(); // Mark all constraints as unevaluated
3401 GetSizer()->LayoutPhase1(&noChanges);
3402 GetSizer()->LayoutPhase2(&noChanges);
3403 GetSizer()->SetConstraintSizes(); // Recursively set the real window sizes
3404 return TRUE;
3405 }
3406 else
3407 {
3408 // Otherwise, evaluate child constraints
3409 ResetConstraints(); // Mark all constraints as unevaluated
3410 DoPhase(1); // Just one phase need if no sizers involved
3411 DoPhase(2);
3412 SetConstraintSizes(); // Recursively set the real window sizes
3413 }
3414 return TRUE;
3415 }
3416
3417
3418 // Do a phase of evaluating constraints:
3419 // the default behaviour. wxSizers may do a similar
3420 // thing, but also impose their own 'constraints'
3421 // and order the evaluation differently.
3422 bool wxWindow::LayoutPhase1(int *noChanges)
3423 {
3424 wxLayoutConstraints *constr = GetConstraints();
3425 if (constr)
3426 {
3427 return constr->SatisfyConstraints((wxWindow *)this, noChanges);
3428 }
3429 else
3430 return TRUE;
3431 }
3432
3433 bool wxWindow::LayoutPhase2(int *noChanges)
3434 {
3435 *noChanges = 0;
3436
3437 // Layout children
3438 DoPhase(1);
3439 DoPhase(2);
3440 return TRUE;
3441 }
3442
3443 // Do a phase of evaluating child constraints
3444 bool wxWindow::DoPhase(int phase)
3445 {
3446 int noIterations = 0;
3447 int maxIterations = 500;
3448 int noChanges = 1;
3449 int noFailures = 0;
3450 wxList succeeded;
3451 while ((noChanges > 0) && (noIterations < maxIterations))
3452 {
3453 noChanges = 0;
3454 noFailures = 0;
3455 wxNode *node = m_children.First();
3456 while (node)
3457 {
3458 wxWindow *child = (wxWindow *)node->Data();
3459 if (!child->IsKindOf(CLASSINFO(wxFrame)) && !child->IsKindOf(CLASSINFO(wxDialog)))
3460 {
3461 wxLayoutConstraints *constr = child->GetConstraints();
3462 if (constr)
3463 {
3464 if (succeeded.Member(child))
3465 {
3466 }
3467 else
3468 {
3469 int tempNoChanges = 0;
3470 bool success = ( (phase == 1) ? child->LayoutPhase1(&tempNoChanges) : child->LayoutPhase2(&tempNoChanges) ) ;
3471 noChanges += tempNoChanges;
3472 if (success)
3473 {
3474 succeeded.Append(child);
3475 }
3476 }
3477 }
3478 }
3479 node = node->Next();
3480 }
3481 noIterations ++;
3482 }
3483 return TRUE;
3484 }
3485
3486 void wxWindow::ResetConstraints()
3487 {
3488 wxLayoutConstraints *constr = GetConstraints();
3489 if (constr)
3490 {
3491 constr->left.SetDone(FALSE);
3492 constr->top.SetDone(FALSE);
3493 constr->right.SetDone(FALSE);
3494 constr->bottom.SetDone(FALSE);
3495 constr->width.SetDone(FALSE);
3496 constr->height.SetDone(FALSE);
3497 constr->centreX.SetDone(FALSE);
3498 constr->centreY.SetDone(FALSE);
3499 }
3500 wxNode *node = m_children.First();
3501 while (node)
3502 {
3503 wxWindow *win = (wxWindow *)node->Data();
3504 if (!win->IsKindOf(CLASSINFO(wxFrame)) && !win->IsKindOf(CLASSINFO(wxDialog)))
3505 win->ResetConstraints();
3506 node = node->Next();
3507 }
3508 }
3509
3510 // Need to distinguish between setting the 'fake' size for
3511 // windows and sizers, and setting the real values.
3512 void wxWindow::SetConstraintSizes(bool recurse)
3513 {
3514 wxLayoutConstraints *constr = GetConstraints();
3515 if (constr && constr->left.GetDone() && constr->right.GetDone() &&
3516 constr->width.GetDone() && constr->height.GetDone())
3517 {
3518 int x = constr->left.GetValue();
3519 int y = constr->top.GetValue();
3520 int w = constr->width.GetValue();
3521 int h = constr->height.GetValue();
3522
3523 // If we don't want to resize this window, just move it...
3524 if ((constr->width.GetRelationship() != wxAsIs) ||
3525 (constr->height.GetRelationship() != wxAsIs))
3526 {
3527 // Calls Layout() recursively. AAAGH. How can we stop that.
3528 // Simply take Layout() out of non-top level OnSizes.
3529 SizerSetSize(x, y, w, h);
3530 }
3531 else
3532 {
3533 SizerMove(x, y);
3534 }
3535 }
3536 else if (constr)
3537 {
3538 wxChar *windowClass = this->GetClassInfo()->GetClassName();
3539
3540 wxString winName;
3541 if (GetName() == _T(""))
3542 winName = _T("unnamed");
3543 else
3544 winName = GetName();
3545 wxLogDebug( _T("Constraint(s) not satisfied for window of type %s, name %s:\n"),
3546 (const wxChar *)windowClass,
3547 (const wxChar *)winName);
3548 if (!constr->left.GetDone()) wxLogDebug( _T(" unsatisfied 'left' constraint.\n") );
3549 if (!constr->right.GetDone()) wxLogDebug( _T(" unsatisfied 'right' constraint.\n") );
3550 if (!constr->width.GetDone()) wxLogDebug( _T(" unsatisfied 'width' constraint.\n") );
3551 if (!constr->height.GetDone()) wxLogDebug( _T(" unsatisfied 'height' constraint.\n") );
3552 wxLogDebug( _T("Please check constraints: try adding AsIs() constraints.\n") );
3553 }
3554
3555 if (recurse)
3556 {
3557 wxNode *node = m_children.First();
3558 while (node)
3559 {
3560 wxWindow *win = (wxWindow *)node->Data();
3561 if (!win->IsKindOf(CLASSINFO(wxFrame)) && !win->IsKindOf(CLASSINFO(wxDialog)))
3562 win->SetConstraintSizes();
3563 node = node->Next();
3564 }
3565 }
3566 }
3567
3568 // This assumes that all sizers are 'on' the same
3569 // window, i.e. the parent of this window.
3570 void wxWindow::TransformSizerToActual(int *x, int *y) const
3571 {
3572 if (!m_sizerParent || m_sizerParent->IsKindOf(CLASSINFO(wxDialog)) ||
3573 m_sizerParent->IsKindOf(CLASSINFO(wxFrame)) )
3574 return;
3575
3576 int xp, yp;
3577 m_sizerParent->GetPosition(&xp, &yp);
3578 m_sizerParent->TransformSizerToActual(&xp, &yp);
3579 *x += xp;
3580 *y += yp;
3581 }
3582
3583 void wxWindow::SizerSetSize(int x, int y, int w, int h)
3584 {
3585 int xx = x;
3586 int yy = y;
3587 TransformSizerToActual(&xx, &yy);
3588 SetSize(xx, yy, w, h);
3589 }
3590
3591 void wxWindow::SizerMove(int x, int y)
3592 {
3593 int xx = x;
3594 int yy = y;
3595 TransformSizerToActual(&xx, &yy);
3596 Move(xx, yy);
3597 }
3598
3599 // Only set the size/position of the constraint (if any)
3600 void wxWindow::SetSizeConstraint(int x, int y, int w, int h)
3601 {
3602 wxLayoutConstraints *constr = GetConstraints();
3603 if (constr)
3604 {
3605 if (x != -1)
3606 {
3607 constr->left.SetValue(x);
3608 constr->left.SetDone(TRUE);
3609 }
3610 if (y != -1)
3611 {
3612 constr->top.SetValue(y);
3613 constr->top.SetDone(TRUE);
3614 }
3615 if (w != -1)
3616 {
3617 constr->width.SetValue(w);
3618 constr->width.SetDone(TRUE);
3619 }
3620 if (h != -1)
3621 {
3622 constr->height.SetValue(h);
3623 constr->height.SetDone(TRUE);
3624 }
3625 }
3626 }
3627
3628 void wxWindow::MoveConstraint(int x, int y)
3629 {
3630 wxLayoutConstraints *constr = GetConstraints();
3631 if (constr)
3632 {
3633 if (x != -1)
3634 {
3635 constr->left.SetValue(x);
3636 constr->left.SetDone(TRUE);
3637 }
3638 if (y != -1)
3639 {
3640 constr->top.SetValue(y);
3641 constr->top.SetDone(TRUE);
3642 }
3643 }
3644 }
3645
3646 void wxWindow::GetSizeConstraint(int *w, int *h) const
3647 {
3648 wxLayoutConstraints *constr = GetConstraints();
3649 if (constr)
3650 {
3651 *w = constr->width.GetValue();
3652 *h = constr->height.GetValue();
3653 }
3654 else
3655 GetSize(w, h);
3656 }
3657
3658 void wxWindow::GetClientSizeConstraint(int *w, int *h) const
3659 {
3660 wxLayoutConstraints *constr = GetConstraints();
3661 if (constr)
3662 {
3663 *w = constr->width.GetValue();
3664 *h = constr->height.GetValue();
3665 }
3666 else
3667 GetClientSize(w, h);
3668 }
3669
3670 void wxWindow::GetPositionConstraint(int *x, int *y) const
3671 {
3672 wxLayoutConstraints *constr = GetConstraints();
3673 if (constr)
3674 {
3675 *x = constr->left.GetValue();
3676 *y = constr->top.GetValue();
3677 }
3678 else
3679 GetPosition(x, y);
3680 }
3681