]> git.saurik.com Git - wxWidgets.git/blob - src/gtk1/window.cpp
Call OnParentEnable from wxTextCtrl::Enable
[wxWidgets.git] / src / gtk1 / window.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: gtk/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 #ifdef __VMS
16 #define XWarpPointer XWARPPOINTER
17 #endif
18
19 #include "wx/defs.h"
20 #include "wx/window.h"
21 #include "wx/dc.h"
22 #include "wx/frame.h"
23 #include "wx/app.h"
24 #include "wx/layout.h"
25 #include "wx/utils.h"
26 #include "wx/dialog.h"
27 #include "wx/msgdlg.h"
28
29 #if wxUSE_DRAG_AND_DROP
30 #include "wx/dnd.h"
31 #endif
32
33 #if wxUSE_TOOLTIPS
34 #include "wx/tooltip.h"
35 #endif
36
37 #if wxUSE_CARET
38 #include "wx/caret.h"
39 #endif // wxUSE_CARET
40
41 #include "wx/menu.h"
42 #include "wx/statusbr.h"
43 #include "wx/intl.h"
44 #include "wx/settings.h"
45 #include "wx/log.h"
46
47 #ifdef __WXDEBUG__
48 #include "wx/thread.h"
49 #endif
50
51 #include <math.h>
52
53 #include <gdk/gdk.h>
54 #include <gtk/gtk.h>
55 #include <gdk/gdkprivate.h>
56 #include <gdk/gdkkeysyms.h>
57 #include <gdk/gdkx.h>
58
59 #include <gtk/gtk.h>
60 #include <gtk/gtkprivate.h>
61
62 #include "wx/gtk/win_gtk.h"
63
64 //-----------------------------------------------------------------------------
65 // documentation on internals
66 //-----------------------------------------------------------------------------
67
68 /*
69 I have been asked several times about writing some documentation about
70 the GTK port of wxWindows, especially its internal structures. Obviously,
71 you cannot understand wxGTK without knowing a little about the GTK, but
72 some more information about what the wxWindow, which is the base class
73 for all other window classes, does seems required as well.
74
75 I)
76
77 What does wxWindow do? It contains the common interface for the following
78 jobs of its descendants:
79
80 1) Define the rudimentary behaviour common to all window classes, such as
81 resizing, intercepting user input (so as to make it possible to use these
82 events for special purposes in a derived class), window names etc.
83
84 2) Provide the possibility to contain and manage children, if the derived
85 class is allowed to contain children, which holds true for those window
86 classes which do not display a native GTK widget. To name them, these
87 classes are wxPanel, wxScrolledWindow, wxDialog, wxFrame. The MDI frame-
88 work classes are a special case and are handled a bit differently from
89 the rest. The same holds true for the wxNotebook class.
90
91 3) Provide the possibility to draw into a client area of a window. This,
92 too, only holds true for classes that do not display a native GTK widget
93 as above.
94
95 4) Provide the entire mechanism for scrolling widgets. This actual inter-
96 face for this is usually in wxScrolledWindow, but the GTK implementation
97 is in this class.
98
99 5) A multitude of helper or extra methods for special purposes, such as
100 Drag'n'Drop, managing validators etc.
101
102 6) Display a border (sunken, raised, simple or none).
103
104 Normally one might expect, that one wxWindows window would always correspond
105 to one GTK widget. Under GTK, there is no such allround widget that has all
106 the functionality. Moreover, the GTK defines a client area as a different
107 widget from the actual widget you are handling. Last but not least some
108 special classes (e.g. wxFrame) handle different categories of widgets and
109 still have the possibility to draw something in the client area.
110 It was therefore required to write a special purpose GTK widget, that would
111 represent a client area in the sense of wxWindows capable to do the jobs
112 2), 3) and 4). I have written this class and it resides in win_gtk.c of
113 this directory.
114
115 All windows must have a widget, with which they interact with other under-
116 lying GTK widgets. It is this widget, e.g. that has to be resized etc and
117 thw wxWindow class has a member variable called m_widget which holds a
118 pointer to this widget. When the window class represents a GTK native widget,
119 this is (in most cases) the only GTK widget the class manages. E.g. the
120 wxStatitText class handles only a GtkLabel widget a pointer to which you
121 can find in m_widget (defined in wxWindow)
122
123 When the class has a client area for drawing into and for containing children
124 it has to handle the client area widget (of the type GtkPizza, defined in
125 win_gtk.c), but there could be any number of widgets, handled by a class
126 The common rule for all windows is only, that the widget that interacts with
127 the rest of GTK must be referenced in m_widget and all other widgets must be
128 children of this widget on the GTK level. The top-most widget, which also
129 represents the client area, must be in the m_wxwindow field and must be of
130 the type GtkPizza.
131
132 As I said, the window classes that display a GTK native widget only have
133 one widget, so in the case of e.g. the wxButton class m_widget holds a
134 pointer to a GtkButton widget. But windows with client areas (for drawing
135 and children) have a m_widget field that is a pointer to a GtkScrolled-
136 Window and a m_wxwindow field that is pointer to a GtkPizza and this
137 one is (in the GTK sense) a child of the GtkScrolledWindow.
138
139 If the m_wxwindow field is set, then all input to this widget is inter-
140 cepted and sent to the wxWindows class. If not, all input to the widget
141 that gets pointed to by m_widget gets intercepted and sent to the class.
142
143 II)
144
145 The design of scrolling in wxWindows is markedly different from that offered
146 by the GTK itself and therefore we cannot simply take it as it is. In GTK,
147 clicking on a scrollbar belonging to scrolled window will inevitably move
148 the window. In wxWindows, the scrollbar will only emit an event, send this
149 to (normally) a wxScrolledWindow and that class will call ScrollWindow()
150 which actually moves the window and its subchildren. Note that GtkPizza
151 memorizes how much it has been scrolled but that wxWindows forgets this
152 so that the two coordinates systems have to be kept in synch. This is done
153 in various places using the pizza->xoffset and pizza->yoffset values.
154
155 III)
156
157 Singularily the most broken code in GTK is the code that is supposes to
158 inform subwindows (child windows) about new positions. Very often, duplicate
159 events are sent without changes in size or position, equally often no
160 events are sent at all (All this is due to a bug in the GtkContainer code
161 which got fixed in GTK 1.2.6). For that reason, wxGTK completely ignores
162 GTK's own system and it simply waits for size events for toplevel windows
163 and then iterates down the respective size events to all window. This has
164 the disadvantage, that windows might get size events before the GTK widget
165 actually has the reported size. This doesn't normally pose any problem, but
166 the OpenGl drawing routines rely on correct behaviour. Therefore, I have
167 added the m_nativeSizeEvents flag, which is true only for the OpenGL canvas,
168 i.e. the wxGLCanvas will emit a size event, when (and not before) the X11
169 window that is used for OpenGl output really has that size (as reported by
170 GTK).
171
172 IV)
173
174 If someone at some point of time feels the immense desire to have a look at,
175 change or attempt to optimse the Refresh() logic, this person will need an
176 intimate understanding of what a "draw" and what an "expose" events are and
177 what there are used for, in particular when used in connection with GTK's
178 own windowless widgets. Beware.
179
180 V)
181
182 Cursors, too, have been a constant source of pleasure. The main difficulty
183 is that a GdkWindow inherits a cursor if the programmer sets a new cursor
184 for the parent. To prevent this from doing too much harm, I use idle time
185 to set the cursor over and over again, starting from the toplevel windows
186 and ending with the youngest generation (speaking of parent and child windows).
187 Also don't forget that cursors (like much else) are connected to GdkWindows,
188 not GtkWidgets and that the "window" field of a GtkWidget might very well
189 point to the GdkWindow of the parent widget (-> "window less widget") and
190 that the two obviously have very different meanings.
191
192 */
193
194 //-----------------------------------------------------------------------------
195 // data
196 //-----------------------------------------------------------------------------
197
198 extern wxList wxPendingDelete;
199 extern bool g_blockEventsOnDrag;
200 extern bool g_blockEventsOnScroll;
201 extern wxCursor g_globalCursor;
202 static wxWindow *g_captureWindow = (wxWindow*) NULL;
203
204 /* extern */ wxWindow *g_focusWindow = (wxWindow*) NULL;
205
206 // if we detect that the app has got/lost the focus, we set this variable to
207 // either TRUE or FALSE and an activate event will be sent during the next
208 // OnIdle() call and it is reset to -1: this value means that we shouldn't
209 // send any activate events at all
210 static int g_sendActivateEvent = -1;
211
212 /* hack: we need something to pass to gtk_menu_popup, so we store the time of
213 the last click here */
214 static guint32 gs_timeLastClick = 0;
215
216 extern bool g_mainThreadLocked;
217
218 //-----------------------------------------------------------------------------
219 // debug
220 //-----------------------------------------------------------------------------
221
222 #ifndef __WXGTK20__
223 #define DISABLE_STYLE_IF_BROKEN_THEME 1
224 #endif
225
226 #ifdef __WXDEBUG__
227
228 #if wxUSE_THREADS
229 # define DEBUG_MAIN_THREAD if (wxThread::IsMain() && g_mainThreadLocked) printf("gui reentrance");
230 #else
231 # define DEBUG_MAIN_THREAD
232 #endif
233
234 static gint gtk_debug_focus_in_callback( GtkWidget *WXUNUSED(widget),
235 GdkEvent *WXUNUSED(event),
236 const wxChar *WXUNUSED(name) )
237 {
238 /*
239 static bool s_done = FALSE;
240 if ( !s_done )
241 {
242 wxLog::AddTraceMask("focus");
243 s_done = TRUE;
244 }
245 wxLogTrace(wxT("FOCUS NOW AT: %s"), name);
246 */
247
248 return FALSE;
249 }
250
251 void debug_focus_in( GtkWidget* widget, const wxChar* name, const wxChar *window )
252 {
253 // suppress warnings about gtk_debug_focus_in_callback being unused with
254 // this "if ( 0 )"
255 if ( 0 )
256 {
257 wxString tmp = name;
258 tmp += wxT(" FROM ");
259 tmp += window;
260
261 wxChar *s = new wxChar[tmp.Length()+1];
262
263 wxStrcpy( s, tmp );
264
265 gtk_signal_connect( GTK_OBJECT(widget), "focus_in_event",
266 GTK_SIGNAL_FUNC(gtk_debug_focus_in_callback), (gpointer)s );
267 }
268 }
269
270 #else
271 #define DEBUG_MAIN_THREAD
272 #endif // Debug
273
274 //-----------------------------------------------------------------------------
275 // missing gdk functions
276 //-----------------------------------------------------------------------------
277
278 void
279 gdk_window_warp_pointer (GdkWindow *window,
280 gint x,
281 gint y)
282 {
283 #ifndef __WXGTK20__
284 GdkWindowPrivate *priv;
285 #endif
286
287 if (!window)
288 window = GDK_ROOT_PARENT();
289
290 #ifdef __WXGTK20__
291 if (!GDK_WINDOW_DESTROYED(window))
292 {
293 XWarpPointer (GDK_WINDOW_XDISPLAY(window),
294 None, /* not source window -> move from anywhere */
295 GDK_WINDOW_XID(window), /* dest window */
296 0, 0, 0, 0, /* not source window -> move from anywhere */
297 x, y );
298 }
299 #else
300 priv = (GdkWindowPrivate*) window;
301
302 if (!priv->destroyed)
303 {
304 XWarpPointer (priv->xdisplay,
305 None, /* not source window -> move from anywhere */
306 priv->xwindow, /* dest window */
307 0, 0, 0, 0, /* not source window -> move from anywhere */
308 x, y );
309 }
310 #endif
311 }
312
313 //-----------------------------------------------------------------------------
314 // idle system
315 //-----------------------------------------------------------------------------
316
317 extern void wxapp_install_idle_handler();
318 extern bool g_isIdle;
319
320 //-----------------------------------------------------------------------------
321 // local code (see below)
322 //-----------------------------------------------------------------------------
323
324 // returns the child of win which currently has focus or NULL if not found
325 // Note: can't be static, needed by textctrl.cpp.
326 /* static */ wxWindow *FindFocusedChild(wxWindow *win)
327 {
328 wxWindow *winFocus = wxWindow::FindFocus();
329 if ( !winFocus )
330 return (wxWindow *)NULL;
331
332 if ( winFocus == win )
333 return win;
334
335 for ( wxWindowList::Node *node = win->GetChildren().GetFirst();
336 node;
337 node = node->GetNext() )
338 {
339 wxWindow *child = FindFocusedChild(node->GetData());
340 if ( child )
341 return child;
342 }
343
344 return (wxWindow *)NULL;
345 }
346
347 static void draw_frame( GtkWidget *widget, wxWindow *win )
348 {
349 if (!win->m_hasVMT)
350 return;
351
352 int dw = 0;
353 int dh = 0;
354
355 if (win->m_hasScrolling)
356 {
357 GtkScrolledWindow *scroll_window = GTK_SCROLLED_WINDOW(widget);
358
359 GtkRequisition vscroll_req;
360 vscroll_req.width = 2;
361 vscroll_req.height = 2;
362 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->vscrollbar) )->size_request )
363 (scroll_window->vscrollbar, &vscroll_req );
364
365 GtkRequisition hscroll_req;
366 hscroll_req.width = 2;
367 hscroll_req.height = 2;
368 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->hscrollbar) )->size_request )
369 (scroll_window->hscrollbar, &hscroll_req );
370
371 GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(widget) );
372
373 if (scroll_window->vscrollbar_visible)
374 {
375 dw += vscroll_req.width;
376 dw += scroll_class->scrollbar_spacing;
377 }
378
379 if (scroll_window->hscrollbar_visible)
380 {
381 dh += hscroll_req.height;
382 dh += scroll_class->scrollbar_spacing;
383 }
384 }
385
386 int dx = 0;
387 int dy = 0;
388 if (GTK_WIDGET_NO_WINDOW (widget))
389 {
390 dx += widget->allocation.x;
391 dy += widget->allocation.y;
392 }
393
394 if (win->HasFlag(wxRAISED_BORDER))
395 {
396 gtk_draw_shadow( widget->style,
397 widget->window,
398 GTK_STATE_NORMAL,
399 GTK_SHADOW_OUT,
400 dx, dy,
401 widget->allocation.width-dw, widget->allocation.height-dh );
402 return;
403 }
404
405 if (win->HasFlag(wxSUNKEN_BORDER))
406 {
407 gtk_draw_shadow( widget->style,
408 widget->window,
409 GTK_STATE_NORMAL,
410 GTK_SHADOW_IN,
411 dx, dy,
412 widget->allocation.width-dw, widget->allocation.height-dh );
413 return;
414 }
415
416 if (win->HasFlag(wxSIMPLE_BORDER))
417 {
418 GdkGC *gc;
419 gc = gdk_gc_new( widget->window );
420 gdk_gc_set_foreground( gc, &widget->style->black );
421 gdk_draw_rectangle( widget->window, gc, FALSE,
422 dx, dy,
423 widget->allocation.width-dw-1, widget->allocation.height-dh-1 );
424 gdk_gc_unref( gc );
425 return;
426 }
427 }
428
429 //-----------------------------------------------------------------------------
430 // "expose_event" of m_widget
431 //-----------------------------------------------------------------------------
432
433 gint gtk_window_own_expose_callback( GtkWidget *widget, GdkEventExpose *gdk_event, wxWindow *win )
434 {
435 if (gdk_event->count > 0) return FALSE;
436
437 draw_frame( widget, win );
438
439 return TRUE;
440 }
441
442 //-----------------------------------------------------------------------------
443 // "draw" of m_widget
444 //-----------------------------------------------------------------------------
445
446 static void gtk_window_own_draw_callback( GtkWidget *widget, GdkRectangle *WXUNUSED(rect), wxWindow *win )
447 {
448 draw_frame( widget, win );
449 }
450
451 //-----------------------------------------------------------------------------
452 // key code mapping routines
453 //-----------------------------------------------------------------------------
454
455 static long map_to_unmodified_wx_keysym( KeySym keysym )
456 {
457 guint key_code = 0;
458
459 switch (keysym)
460 {
461 case GDK_Shift_L:
462 case GDK_Shift_R: key_code = WXK_SHIFT; break;
463 case GDK_Control_L:
464 case GDK_Control_R: key_code = WXK_CONTROL; break;
465 case GDK_Meta_L:
466 case GDK_Meta_R:
467 case GDK_Alt_L:
468 case GDK_Alt_R:
469 case GDK_Super_L:
470 case GDK_Super_R: key_code = WXK_ALT; break;
471 case GDK_Menu: key_code = WXK_MENU; break;
472 case GDK_Help: key_code = WXK_HELP; break;
473 case GDK_BackSpace: key_code = WXK_BACK; break;
474 case GDK_ISO_Left_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
500 case GDK_KP_0: key_code = WXK_NUMPAD0; break;
501 case GDK_KP_1: key_code = WXK_NUMPAD1; break;
502 case GDK_KP_2: key_code = WXK_NUMPAD2; break;
503 case GDK_KP_3: key_code = WXK_NUMPAD3; break;
504 case GDK_KP_4: key_code = WXK_NUMPAD4; break;
505 case GDK_KP_5: key_code = WXK_NUMPAD5; break;
506 case GDK_KP_6: key_code = WXK_NUMPAD6; break;
507 case GDK_KP_7: key_code = WXK_NUMPAD7; break;
508 case GDK_KP_8: key_code = WXK_NUMPAD8; break;
509 case GDK_KP_9: key_code = WXK_NUMPAD9; break;
510 case GDK_KP_Space: key_code = WXK_NUMPAD_SPACE; break;
511 case GDK_KP_Tab: key_code = WXK_NUMPAD_TAB; break;
512 case GDK_KP_Enter: key_code = WXK_NUMPAD_ENTER; break;
513 case GDK_KP_F1: key_code = WXK_NUMPAD_F1; break;
514 case GDK_KP_F2: key_code = WXK_NUMPAD_F2; break;
515 case GDK_KP_F3: key_code = WXK_NUMPAD_F3; break;
516 case GDK_KP_F4: key_code = WXK_NUMPAD_F4; break;
517 case GDK_KP_Home: key_code = WXK_NUMPAD_HOME; break;
518 case GDK_KP_Left: key_code = WXK_NUMPAD_LEFT; break;
519 case GDK_KP_Up: key_code = WXK_NUMPAD_UP; break;
520 case GDK_KP_Right: key_code = WXK_NUMPAD_RIGHT; break;
521 case GDK_KP_Down: key_code = WXK_NUMPAD_DOWN; break;
522 case GDK_KP_Prior: key_code = WXK_NUMPAD_PRIOR; break;
523 // case GDK_KP_Page_Up: key_code = WXK_NUMPAD_PAGEUP; break;
524 case GDK_KP_Next: key_code = WXK_NUMPAD_NEXT; break;
525 // case GDK_KP_Page_Down: key_code = WXK_NUMPAD_PAGEDOWN; break;
526 case GDK_KP_End: key_code = WXK_NUMPAD_END; break;
527 case GDK_KP_Begin: key_code = WXK_NUMPAD_BEGIN; break;
528 case GDK_KP_Insert: key_code = WXK_NUMPAD_INSERT; break;
529 case GDK_KP_Delete: key_code = WXK_NUMPAD_DELETE; break;
530 case GDK_KP_Equal: key_code = WXK_NUMPAD_EQUAL; break;
531 case GDK_KP_Multiply: key_code = WXK_NUMPAD_MULTIPLY; break;
532 case GDK_KP_Add: key_code = WXK_NUMPAD_ADD; break;
533 case GDK_KP_Separator: key_code = WXK_NUMPAD_SEPARATOR; break;
534 case GDK_KP_Subtract: key_code = WXK_NUMPAD_SUBTRACT; break;
535 case GDK_KP_Decimal: key_code = WXK_NUMPAD_DECIMAL; break;
536 case GDK_KP_Divide: key_code = WXK_NUMPAD_DIVIDE; break;
537
538 case GDK_F1: key_code = WXK_F1; break;
539 case GDK_F2: key_code = WXK_F2; break;
540 case GDK_F3: key_code = WXK_F3; break;
541 case GDK_F4: key_code = WXK_F4; break;
542 case GDK_F5: key_code = WXK_F5; break;
543 case GDK_F6: key_code = WXK_F6; break;
544 case GDK_F7: key_code = WXK_F7; break;
545 case GDK_F8: key_code = WXK_F8; break;
546 case GDK_F9: key_code = WXK_F9; break;
547 case GDK_F10: key_code = WXK_F10; break;
548 case GDK_F11: key_code = WXK_F11; break;
549 case GDK_F12: key_code = WXK_F12; break;
550 default:
551 {
552 if ((keysym & 0xF000) == 0)
553 {
554 guint upper = gdk_keyval_to_upper( (guint)keysym );
555 keysym = (upper != 0 ? upper : keysym ); /* to be MSW compatible */
556 key_code = (guint)keysym;
557 }
558 }
559 }
560
561 return (key_code);
562 }
563
564 static long map_to_wx_keysym( KeySym keysym )
565 {
566 guint key_code = 0;
567
568 switch (keysym)
569 {
570 case GDK_Menu: key_code = WXK_MENU; break;
571 case GDK_Help: key_code = WXK_HELP; break;
572 case GDK_BackSpace: key_code = WXK_BACK; break;
573 case GDK_ISO_Left_Tab:
574 case GDK_Tab: key_code = WXK_TAB; break;
575 case GDK_Linefeed: key_code = WXK_RETURN; break;
576 case GDK_Clear: key_code = WXK_CLEAR; break;
577 case GDK_Return: key_code = WXK_RETURN; break;
578 case GDK_Pause: key_code = WXK_PAUSE; break;
579 case GDK_Scroll_Lock: key_code = WXK_SCROLL; break;
580 case GDK_Escape: key_code = WXK_ESCAPE; break;
581 case GDK_Delete: key_code = WXK_DELETE; break;
582 case GDK_Home: key_code = WXK_HOME; break;
583 case GDK_Left: key_code = WXK_LEFT; break;
584 case GDK_Up: key_code = WXK_UP; break;
585 case GDK_Right: key_code = WXK_RIGHT; break;
586 case GDK_Down: key_code = WXK_DOWN; break;
587 case GDK_Prior: key_code = WXK_PRIOR; break;
588 // case GDK_Page_Up: key_code = WXK_PAGEUP; break;
589 case GDK_Next: key_code = WXK_NEXT; break;
590 // case GDK_Page_Down: key_code = WXK_PAGEDOWN; break;
591 case GDK_End: key_code = WXK_END; break;
592 case GDK_Begin: key_code = WXK_HOME; break;
593 case GDK_Select: key_code = WXK_SELECT; break;
594 case GDK_Print: key_code = WXK_PRINT; break;
595 case GDK_Execute: key_code = WXK_EXECUTE; break;
596 case GDK_Insert: key_code = WXK_INSERT; break;
597 case GDK_Num_Lock: key_code = WXK_NUMLOCK; break;
598
599 case GDK_KP_0: key_code = '0'; break;
600 case GDK_KP_1: key_code = '1'; break;
601 case GDK_KP_2: key_code = '2'; break;
602 case GDK_KP_3: key_code = '3'; break;
603 case GDK_KP_4: key_code = '4'; break;
604 case GDK_KP_5: key_code = '5'; break;
605 case GDK_KP_6: key_code = '6'; break;
606 case GDK_KP_7: key_code = '7'; break;
607 case GDK_KP_8: key_code = '8'; break;
608 case GDK_KP_9: key_code = '9'; break;
609 case GDK_KP_Space: key_code = ' '; break;
610 case GDK_KP_Tab: key_code = WXK_TAB; break; /* or '\t' ??? */
611 case GDK_KP_Enter: key_code = WXK_RETURN; break; /* or '\r' ??? */
612 case GDK_KP_F1: key_code = WXK_NUMPAD_F1; break;
613 case GDK_KP_F2: key_code = WXK_NUMPAD_F2; break;
614 case GDK_KP_F3: key_code = WXK_NUMPAD_F3; break;
615 case GDK_KP_F4: key_code = WXK_NUMPAD_F4; break;
616 case GDK_KP_Home: key_code = WXK_HOME; break;
617 case GDK_KP_Left: key_code = WXK_LEFT; break;
618 case GDK_KP_Up: key_code = WXK_UP; break;
619 case GDK_KP_Right: key_code = WXK_RIGHT; break;
620 case GDK_KP_Down: key_code = WXK_DOWN; break;
621 case GDK_KP_Prior: key_code = WXK_PRIOR; break;
622 // case GDK_KP_Page_Up: key_code = WXK_PAGEUP; break;
623 case GDK_KP_Next: key_code = WXK_NEXT; break;
624 // case GDK_KP_Page_Down: key_code = WXK_PAGEDOWN; break;
625 case GDK_KP_End: key_code = WXK_END; break;
626 case GDK_KP_Begin: key_code = WXK_HOME; break;
627 case GDK_KP_Insert: key_code = WXK_INSERT; break;
628 case GDK_KP_Delete: key_code = WXK_DELETE; break;
629 case GDK_KP_Equal: key_code = '='; break;
630 case GDK_KP_Multiply: key_code = '*'; break;
631 case GDK_KP_Add: key_code = '+'; break;
632 case GDK_KP_Separator: key_code = ','; break;
633 case GDK_KP_Subtract: key_code = '-'; break;
634 case GDK_KP_Decimal: key_code = '.'; break;
635 case GDK_KP_Divide: key_code = '/'; break;
636
637 case GDK_F1: key_code = WXK_F1; break;
638 case GDK_F2: key_code = WXK_F2; break;
639 case GDK_F3: key_code = WXK_F3; break;
640 case GDK_F4: key_code = WXK_F4; break;
641 case GDK_F5: key_code = WXK_F5; break;
642 case GDK_F6: key_code = WXK_F6; break;
643 case GDK_F7: key_code = WXK_F7; break;
644 case GDK_F8: key_code = WXK_F8; break;
645 case GDK_F9: key_code = WXK_F9; break;
646 case GDK_F10: key_code = WXK_F10; break;
647 case GDK_F11: key_code = WXK_F11; break;
648 case GDK_F12: key_code = WXK_F12; break;
649 default:
650 {
651 if ((keysym & 0xF000) == 0)
652 {
653 key_code = (guint)keysym;
654 }
655 }
656 }
657
658 return (key_code);
659 }
660
661 //-----------------------------------------------------------------------------
662 // "size_request" of m_widget
663 //-----------------------------------------------------------------------------
664
665 static void gtk_window_size_request_callback( GtkWidget *widget, GtkRequisition *requisition, wxWindow *win )
666 {
667 int w,h;
668 win->GetSize( &w, &h );
669 if (w < 2) w = 2;
670 if (h < 2) h = 2;
671
672 requisition->height = h;
673 requisition->width = w;
674 }
675
676 //-----------------------------------------------------------------------------
677 // "expose_event" of m_wxwindow
678 //-----------------------------------------------------------------------------
679
680 static int gtk_window_expose_callback( GtkWidget *widget, GdkEventExpose *gdk_event, wxWindow *win )
681 {
682 DEBUG_MAIN_THREAD
683
684 if (g_isIdle)
685 wxapp_install_idle_handler();
686
687 /*
688 if (win->GetName() == wxT("panel"))
689 {
690 wxPrintf( wxT("OnExpose from ") );
691 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
692 wxPrintf( win->GetClassInfo()->GetClassName() );
693 wxPrintf( wxT(" %d %d %d %d\n"), (int)gdk_event->area.x,
694 (int)gdk_event->area.y,
695 (int)gdk_event->area.width,
696 (int)gdk_event->area.height );
697 }
698 */
699
700 GtkPizza *pizza = GTK_PIZZA (widget);
701
702 if (win->GetThemeEnabled())
703 {
704 wxWindow *parent = win->GetParent();
705 while (parent && !parent->IsTopLevel())
706 parent = parent->GetParent();
707 if (!parent)
708 parent = win;
709
710 gtk_paint_flat_box (parent->m_widget->style, pizza->bin_window, GTK_STATE_NORMAL,
711 GTK_SHADOW_NONE, &gdk_event->area, parent->m_widget, "base", 0, 0, -1, -1);
712 }
713
714 win->GetUpdateRegion().Union( gdk_event->area.x,
715 gdk_event->area.y,
716 gdk_event->area.width,
717 gdk_event->area.height );
718
719 if (gdk_event->count == 0)
720 {
721 win->m_clipPaintRegion = TRUE;
722
723 wxEraseEvent eevent( win->GetId() );
724 eevent.SetEventObject( win );
725 win->GetEventHandler()->ProcessEvent(eevent);
726
727 wxPaintEvent event( win->GetId() );
728 event.SetEventObject( win );
729 win->GetEventHandler()->ProcessEvent( event );
730
731 win->GetUpdateRegion().Clear();
732
733 win->m_clipPaintRegion = FALSE;
734 }
735
736 /* The following code will result in all window-less widgets
737 being redrawn if the wxWindows class is given a chance to
738 paint *anything* because it will then be allowed to paint
739 over the window-less widgets */
740
741 GList *children = pizza->children;
742 while (children)
743 {
744 GtkPizzaChild *child = (GtkPizzaChild*) children->data;
745 children = children->next;
746
747 GdkEventExpose child_event = *gdk_event;
748
749 if (GTK_WIDGET_NO_WINDOW (child->widget) &&
750 GTK_WIDGET_DRAWABLE (child->widget) /* &&
751 gtk_widget_intersect (child->widget, &gdk_event->area, &child_event.area)*/ )
752 {
753 child_event.area.x = child->widget->allocation.x;
754 child_event.area.y = child->widget->allocation.y;
755 child_event.area.width = child->widget->allocation.width;
756 child_event.area.height = child->widget->allocation.height;
757 gtk_widget_event (child->widget, (GdkEvent*) &child_event);
758 }
759 }
760
761 return TRUE;
762 }
763
764 //-----------------------------------------------------------------------------
765 // "event" of m_wxwindow
766 //-----------------------------------------------------------------------------
767
768 /* GTK thinks it is clever and filters out a certain amount of "unneeded"
769 expose events. We need them, of course, so we override the main event
770 procedure in GtkWidget by giving our own handler for all system events.
771 There, we look for expose events ourselves whereas all other events are
772 handled normally. */
773
774 gint gtk_window_event_event_callback( GtkWidget *widget, GdkEventExpose *event, wxWindow *win )
775 {
776 if (event->type == GDK_EXPOSE)
777 {
778 gint ret = gtk_window_expose_callback( widget, event, win );
779 return ret;
780 }
781
782 return FALSE;
783 }
784
785 //-----------------------------------------------------------------------------
786 // "draw" of m_wxwindow
787 //-----------------------------------------------------------------------------
788
789 /* This callback is a complete replacement of the gtk_pizza_draw() function,
790 which disabled. */
791
792 static void gtk_window_draw_callback( GtkWidget *widget, GdkRectangle *rect, wxWindow *win )
793 {
794 DEBUG_MAIN_THREAD
795
796 if (g_isIdle)
797 wxapp_install_idle_handler();
798
799 if ((win->HasFlag(wxNO_FULL_REPAINT_ON_RESIZE)) &&
800 (win->GetChildren().GetCount() == 0))
801 {
802 return;
803 }
804
805 /*
806 if (win->GetName() == wxT("panel"))
807 {
808 wxPrintf( wxT("OnDraw from ") );
809 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
810 wxPrintf( win->GetClassInfo()->GetClassName() );
811 wxPrintf( wxT(" %d %d %d %d\n"), (int)rect->x,
812 (int)rect->y,
813 (int)rect->width,
814 (int)rect->height );
815 }
816 */
817
818 GtkPizza *pizza = GTK_PIZZA (widget);
819
820 if (win->GetThemeEnabled())
821 {
822 wxWindow *parent = win->GetParent();
823 while (parent && !parent->IsTopLevel())
824 parent = parent->GetParent();
825 if (!parent)
826 parent = win;
827
828 gtk_paint_flat_box (parent->m_widget->style, pizza->bin_window, GTK_STATE_NORMAL,
829 GTK_SHADOW_NONE, rect, parent->m_widget, "base", 0, 0, -1, -1);
830 }
831
832
833 if (!(GTK_WIDGET_APP_PAINTABLE (widget)) &&
834 (pizza->clear_on_draw))
835 {
836 gdk_window_clear_area( pizza->bin_window,
837 rect->x, rect->y, rect->width, rect->height);
838 }
839
840 win->GetUpdateRegion().Union( rect->x, rect->y, rect->width, rect->height );
841
842 win->m_clipPaintRegion = TRUE;
843
844 wxEraseEvent eevent( win->GetId() );
845 eevent.SetEventObject( win );
846 win->GetEventHandler()->ProcessEvent(eevent);
847
848 wxPaintEvent event( win->GetId() );
849 event.SetEventObject( win );
850 win->GetEventHandler()->ProcessEvent( event );
851
852 win->GetUpdateRegion().Clear();
853
854 win->m_clipPaintRegion = FALSE;
855
856
857 GList *children = pizza->children;
858 while (children)
859 {
860 GtkPizzaChild *child = (GtkPizzaChild*) children->data;
861 children = children->next;
862
863 GdkRectangle child_area;
864 if (gtk_widget_intersect (child->widget, rect, &child_area))
865 {
866 gtk_widget_draw (child->widget, &child_area /* (GdkRectangle*) NULL*/ );
867 }
868 }
869 }
870
871 //-----------------------------------------------------------------------------
872 // "key_press_event" from any window
873 //-----------------------------------------------------------------------------
874
875 static gint gtk_window_key_press_callback( GtkWidget *widget, GdkEventKey *gdk_event, wxWindow *win )
876 {
877 DEBUG_MAIN_THREAD
878
879 if (g_isIdle)
880 wxapp_install_idle_handler();
881
882 if (!win->m_hasVMT) return FALSE;
883 if (g_blockEventsOnDrag) return FALSE;
884
885
886 /*
887 wxString tmp;
888 tmp += (char)gdk_event->keyval;
889 printf( "KeyDown-Code is: %s.\n", tmp.c_str() );
890 printf( "KeyDown-ScanCode is: %d.\n", gdk_event->keyval );
891 */
892
893 int x = 0;
894 int y = 0;
895 GdkModifierType state;
896 if (gdk_event->window) gdk_window_get_pointer(gdk_event->window, &x, &y, &state);
897
898 bool ret = FALSE;
899
900 long key_code = map_to_unmodified_wx_keysym( gdk_event->keyval );
901 /* sending unknown key events doesn't really make sense */
902 if (key_code == 0) return FALSE;
903
904 wxKeyEvent event( wxEVT_KEY_DOWN );
905 event.SetTimestamp( gdk_event->time );
906 event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK);
907 event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK);
908 event.m_altDown = (gdk_event->state & GDK_MOD1_MASK);
909 event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK);
910 event.m_keyCode = key_code;
911 event.m_scanCode = gdk_event->keyval;
912 event.m_x = x;
913 event.m_y = y;
914 event.SetEventObject( win );
915 ret = win->GetEventHandler()->ProcessEvent( event );
916
917 #if wxUSE_ACCEL
918 if (!ret)
919 {
920 wxWindow *ancestor = win;
921 while (ancestor)
922 {
923 int command = ancestor->GetAcceleratorTable()->GetCommand( event );
924 if (command != -1)
925 {
926 wxCommandEvent command_event( wxEVT_COMMAND_MENU_SELECTED, command );
927 ret = ancestor->GetEventHandler()->ProcessEvent( command_event );
928 break;
929 }
930 if (ancestor->IsTopLevel())
931 break;
932 ancestor = ancestor->GetParent();
933 }
934 }
935 #endif // wxUSE_ACCEL
936
937 /* wxMSW doesn't send char events with Alt pressed */
938 /* Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x
939 will only be sent if it is not in an accelerator table. */
940 key_code = map_to_wx_keysym( gdk_event->keyval );
941
942 if ( (!ret) &&
943 (key_code != 0))
944 {
945 wxKeyEvent event2( wxEVT_CHAR );
946 event2.SetTimestamp( gdk_event->time );
947 event2.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK);
948 event2.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK);
949 event2.m_altDown = (gdk_event->state & GDK_MOD1_MASK);
950 event2.m_metaDown = (gdk_event->state & GDK_MOD2_MASK);
951 event2.m_keyCode = key_code;
952 event2.m_scanCode = gdk_event->keyval;
953 event2.m_x = x;
954 event2.m_y = y;
955 event2.SetEventObject( win );
956 ret = win->GetEventHandler()->ProcessEvent( event2 );
957 }
958
959 /* win is a control: tab can be propagated up */
960 if ( (!ret) &&
961 ((gdk_event->keyval == GDK_Tab) || (gdk_event->keyval == GDK_ISO_Left_Tab)) &&
962 // VZ: testing for wxTE_PROCESS_TAB shouldn't be done here the control may
963 // have this style, yet choose not to process this particular TAB in which
964 // case TAB must still work as a navigational character
965 #if 0
966 (!win->HasFlag(wxTE_PROCESS_TAB)) &&
967 #endif // 0
968 (win->GetParent()) &&
969 (win->GetParent()->HasFlag( wxTAB_TRAVERSAL)) )
970 {
971 wxNavigationKeyEvent new_event;
972 new_event.SetEventObject( win->GetParent() );
973 /* GDK reports GDK_ISO_Left_Tab for SHIFT-TAB */
974 new_event.SetDirection( (gdk_event->keyval == GDK_Tab) );
975 /* CTRL-TAB changes the (parent) window, i.e. switch notebook page */
976 new_event.SetWindowChange( (gdk_event->state & GDK_CONTROL_MASK) );
977 new_event.SetCurrentFocus( win );
978 ret = win->GetParent()->GetEventHandler()->ProcessEvent( new_event );
979 }
980
981 /* generate wxID_CANCEL if <esc> has been pressed (typically in dialogs) */
982 if ( (!ret) &&
983 (gdk_event->keyval == GDK_Escape) )
984 {
985 wxCommandEvent new_event(wxEVT_COMMAND_BUTTON_CLICKED,wxID_CANCEL);
986 new_event.SetEventObject( win );
987 ret = win->GetEventHandler()->ProcessEvent( new_event );
988 }
989
990 #if (GTK_MINOR_VERSION > 0)
991 /* Pressing F10 will activate the menu bar of the top frame. */
992 /* Doesn't work. */
993 /*
994 if ( (!ret) &&
995 (gdk_event->keyval == GDK_F10) )
996 {
997 wxWindow *ancestor = win;
998 while (ancestor)
999 {
1000 if (wxIsKindOf(ancestor,wxFrame))
1001 {
1002 wxFrame *frame = (wxFrame*) ancestor;
1003 wxMenuBar *menubar = frame->GetMenuBar();
1004 if (menubar)
1005 {
1006 wxNode *node = menubar->GetMenus().First();
1007 if (node)
1008 {
1009 wxMenu *firstMenu = (wxMenu*) node->Data();
1010 gtk_menu_item_select( GTK_MENU_ITEM(firstMenu->m_owner) );
1011 ret = TRUE;
1012 break;
1013 }
1014 }
1015 }
1016 ancestor = ancestor->GetParent();
1017 }
1018 }
1019 */
1020 #endif
1021
1022 if (ret)
1023 {
1024 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "key_press_event" );
1025 return TRUE;
1026 }
1027
1028 return FALSE;
1029 }
1030
1031 //-----------------------------------------------------------------------------
1032 // "key_release_event" from any window
1033 //-----------------------------------------------------------------------------
1034
1035 static gint gtk_window_key_release_callback( GtkWidget *widget, GdkEventKey *gdk_event, wxWindow *win )
1036 {
1037 DEBUG_MAIN_THREAD
1038
1039 if (g_isIdle)
1040 wxapp_install_idle_handler();
1041
1042 if (!win->m_hasVMT) return FALSE;
1043 if (g_blockEventsOnDrag) return FALSE;
1044
1045 /*
1046 printf( "KeyUp-ScanCode is: %d.\n", gdk_event->keyval );
1047 if (gdk_event->state & GDK_SHIFT_MASK)
1048 printf( "ShiftDown.\n" );
1049 else
1050 printf( "ShiftUp.\n" );
1051 if (gdk_event->state & GDK_CONTROL_MASK)
1052 printf( "ControlDown.\n" );
1053 else
1054 printf( "ControlUp.\n" );
1055 printf( "\n" );
1056 */
1057
1058 long key_code = map_to_unmodified_wx_keysym( gdk_event->keyval );
1059
1060 /* sending unknown key events doesn't really make sense */
1061 if (key_code == 0) return FALSE;
1062
1063 int x = 0;
1064 int y = 0;
1065 GdkModifierType state;
1066 if (gdk_event->window) gdk_window_get_pointer(gdk_event->window, &x, &y, &state);
1067
1068 wxKeyEvent event( wxEVT_KEY_UP );
1069 event.SetTimestamp( gdk_event->time );
1070 event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK);
1071 event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK);
1072 event.m_altDown = (gdk_event->state & GDK_MOD1_MASK);
1073 event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK);
1074 event.m_keyCode = key_code;
1075 event.m_scanCode = gdk_event->keyval;
1076 event.m_x = x;
1077 event.m_y = y;
1078 event.SetEventObject( win );
1079
1080 if (win->GetEventHandler()->ProcessEvent( event ))
1081 {
1082 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "key_release_event" );
1083 return TRUE;
1084 }
1085
1086 return FALSE;
1087 }
1088
1089 // ----------------------------------------------------------------------------
1090 // mouse event processing helper
1091 // ----------------------------------------------------------------------------
1092
1093 static void AdjustEventButtonState(wxMouseEvent& event)
1094 {
1095 // GDK reports the old state of the button for a button press event, but
1096 // for compatibility with MSW and common sense we want m_leftDown be TRUE
1097 // for a LEFT_DOWN event, not FALSE, so we will invert
1098 // left/right/middleDown for the corresponding click events
1099
1100 if ((event.GetEventType() == wxEVT_LEFT_DOWN) ||
1101 (event.GetEventType() == wxEVT_LEFT_DCLICK) ||
1102 (event.GetEventType() == wxEVT_LEFT_UP))
1103 {
1104 event.m_leftDown = !event.m_leftDown;
1105 return;
1106 }
1107
1108 if ((event.GetEventType() == wxEVT_MIDDLE_DOWN) ||
1109 (event.GetEventType() == wxEVT_MIDDLE_DCLICK) ||
1110 (event.GetEventType() == wxEVT_MIDDLE_UP))
1111 {
1112 event.m_middleDown = !event.m_middleDown;
1113 return;
1114 }
1115
1116 if ((event.GetEventType() == wxEVT_RIGHT_DOWN) ||
1117 (event.GetEventType() == wxEVT_RIGHT_DCLICK) ||
1118 (event.GetEventType() == wxEVT_RIGHT_UP))
1119 {
1120 event.m_rightDown = !event.m_rightDown;
1121 return;
1122 }
1123 }
1124
1125 //-----------------------------------------------------------------------------
1126 // "button_press_event"
1127 //-----------------------------------------------------------------------------
1128
1129 static gint gtk_window_button_press_callback( GtkWidget *widget, GdkEventButton *gdk_event, wxWindow *win )
1130 {
1131 DEBUG_MAIN_THREAD
1132
1133 if (g_isIdle)
1134 wxapp_install_idle_handler();
1135
1136 /*
1137 wxPrintf( wxT("1) OnButtonPress from ") );
1138 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1139 wxPrintf( win->GetClassInfo()->GetClassName() );
1140 wxPrintf( wxT(".\n") );
1141 */
1142 if (!win->m_hasVMT) return FALSE;
1143 if (g_blockEventsOnDrag) return TRUE;
1144 if (g_blockEventsOnScroll) return TRUE;
1145
1146 if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
1147
1148 if (win->m_wxwindow)
1149 {
1150 if (GTK_WIDGET_CAN_FOCUS(win->m_wxwindow) && !GTK_WIDGET_HAS_FOCUS (win->m_wxwindow) )
1151 {
1152 gtk_widget_grab_focus (win->m_wxwindow);
1153
1154 /*
1155 wxPrintf( wxT("GrabFocus from ") );
1156 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1157 wxPrintf( win->GetClassInfo()->GetClassName() );
1158 wxPrintf( wxT(".\n") );
1159 */
1160
1161 }
1162 }
1163
1164 wxEventType event_type = wxEVT_NULL;
1165
1166 if (gdk_event->button == 1)
1167 {
1168 switch (gdk_event->type)
1169 {
1170 case GDK_BUTTON_PRESS: event_type = wxEVT_LEFT_DOWN; break;
1171 case GDK_2BUTTON_PRESS: event_type = wxEVT_LEFT_DCLICK; break;
1172 default: break;
1173 }
1174 }
1175 else if (gdk_event->button == 2)
1176 {
1177 switch (gdk_event->type)
1178 {
1179 case GDK_BUTTON_PRESS: event_type = wxEVT_MIDDLE_DOWN; break;
1180 case GDK_2BUTTON_PRESS: event_type = wxEVT_MIDDLE_DCLICK; break;
1181 default: break;
1182 }
1183 }
1184 else if (gdk_event->button == 3)
1185 {
1186 switch (gdk_event->type)
1187 {
1188 case GDK_BUTTON_PRESS: event_type = wxEVT_RIGHT_DOWN; break;
1189 case GDK_2BUTTON_PRESS: event_type = wxEVT_RIGHT_DCLICK; break;
1190 default: break;
1191 }
1192 }
1193
1194 if ( event_type == wxEVT_NULL )
1195 {
1196 // unknown mouse button or click type
1197 return FALSE;
1198 }
1199
1200 wxMouseEvent event( event_type );
1201 event.SetTimestamp( gdk_event->time );
1202 event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK);
1203 event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK);
1204 event.m_altDown = (gdk_event->state & GDK_MOD1_MASK);
1205 event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK);
1206 event.m_leftDown = (gdk_event->state & GDK_BUTTON1_MASK);
1207 event.m_middleDown = (gdk_event->state & GDK_BUTTON2_MASK);
1208 event.m_rightDown = (gdk_event->state & GDK_BUTTON3_MASK);
1209
1210 event.m_x = (wxCoord)gdk_event->x;
1211 event.m_y = (wxCoord)gdk_event->y;
1212
1213 AdjustEventButtonState(event);
1214
1215 // Some control don't have their own X window and thus cannot get
1216 // any events.
1217
1218 if (!g_captureWindow)
1219 {
1220 wxCoord x = event.m_x;
1221 wxCoord y = event.m_y;
1222 if (win->m_wxwindow)
1223 {
1224 GtkPizza *pizza = GTK_PIZZA(win->m_wxwindow);
1225 x += pizza->xoffset;
1226 y += pizza->yoffset;
1227 }
1228
1229 wxNode *node = win->GetChildren().First();
1230 while (node)
1231 {
1232 wxWindow *child = (wxWindow*)node->Data();
1233
1234 node = node->Next();
1235 if (!child->IsShown())
1236 continue;
1237
1238 if (child->m_isStaticBox)
1239 {
1240 // wxStaticBox is transparent in the box itself
1241 int xx1 = child->m_x;
1242 int yy1 = child->m_y;
1243 int xx2 = child->m_x + child->m_width;
1244 int yy2 = child->m_x + child->m_height;
1245
1246 // left
1247 if (((x >= xx1) && (x <= xx1+10) && (y >= yy1) && (y <= yy2)) ||
1248 // right
1249 ((x >= xx2-10) && (x <= xx2) && (y >= yy1) && (y <= yy2)) ||
1250 // top
1251 ((x >= xx1) && (x <= xx2) && (y >= yy1) && (y <= yy1+10)) ||
1252 // bottom
1253 ((x >= xx1) && (x <= xx2) && (y >= yy2-1) && (y <= yy2)))
1254 {
1255 win = child;
1256 event.m_x -= child->m_x;
1257 event.m_y -= child->m_y;
1258 break;
1259 }
1260
1261 }
1262 else
1263 {
1264 if ((child->m_wxwindow == (GtkWidget*) NULL) &&
1265 (child->m_x <= x) &&
1266 (child->m_y <= y) &&
1267 (child->m_x+child->m_width >= x) &&
1268 (child->m_y+child->m_height >= y))
1269 {
1270 win = child;
1271 event.m_x -= child->m_x;
1272 event.m_y -= child->m_y;
1273 break;
1274 }
1275 }
1276 }
1277 }
1278
1279 event.SetEventObject( win );
1280
1281 gs_timeLastClick = gdk_event->time;
1282
1283 /*
1284 wxPrintf( wxT("2) OnButtonPress from ") );
1285 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1286 wxPrintf( win->GetClassInfo()->GetClassName() );
1287 wxPrintf( wxT(".\n") );
1288 */
1289
1290 if (win->GetEventHandler()->ProcessEvent( event ))
1291 {
1292 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "button_press_event" );
1293 return TRUE;
1294 }
1295
1296 return FALSE;
1297 }
1298
1299 //-----------------------------------------------------------------------------
1300 // "button_release_event"
1301 //-----------------------------------------------------------------------------
1302
1303 static gint gtk_window_button_release_callback( GtkWidget *widget, GdkEventButton *gdk_event, wxWindow *win )
1304 {
1305 DEBUG_MAIN_THREAD
1306
1307 if (g_isIdle)
1308 wxapp_install_idle_handler();
1309
1310 if (!win->m_hasVMT) return FALSE;
1311 if (g_blockEventsOnDrag) return FALSE;
1312 if (g_blockEventsOnScroll) return FALSE;
1313
1314 if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
1315
1316 /*
1317 printf( "OnButtonRelease from " );
1318 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1319 printf( win->GetClassInfo()->GetClassName() );
1320 printf( ".\n" );
1321 */
1322
1323 wxEventType event_type = wxEVT_NULL;
1324
1325 switch (gdk_event->button)
1326 {
1327 case 1: event_type = wxEVT_LEFT_UP; break;
1328 case 2: event_type = wxEVT_MIDDLE_UP; break;
1329 case 3: event_type = wxEVT_RIGHT_UP; break;
1330 default: return FALSE;
1331 }
1332
1333 wxMouseEvent event( event_type );
1334 event.SetTimestamp( gdk_event->time );
1335 event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK);
1336 event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK);
1337 event.m_altDown = (gdk_event->state & GDK_MOD1_MASK);
1338 event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK);
1339 event.m_leftDown = (gdk_event->state & GDK_BUTTON1_MASK);
1340 event.m_middleDown = (gdk_event->state & GDK_BUTTON2_MASK);
1341 event.m_rightDown = (gdk_event->state & GDK_BUTTON3_MASK);
1342 event.m_x = (wxCoord)gdk_event->x;
1343 event.m_y = (wxCoord)gdk_event->y;
1344
1345 AdjustEventButtonState(event);
1346
1347 // Some control don't have their own X window and thus cannot get
1348 // any events.
1349
1350 if (!g_captureWindow)
1351 {
1352 wxCoord x = event.m_x;
1353 wxCoord y = event.m_y;
1354 if (win->m_wxwindow)
1355 {
1356 GtkPizza *pizza = GTK_PIZZA(win->m_wxwindow);
1357 x += pizza->xoffset;
1358 y += pizza->yoffset;
1359 }
1360
1361 wxNode *node = win->GetChildren().First();
1362 while (node)
1363 {
1364 wxWindow *child = (wxWindow*)node->Data();
1365
1366 node = node->Next();
1367 if (!child->IsShown())
1368 continue;
1369
1370 if (child->m_isStaticBox)
1371 {
1372 // wxStaticBox is transparent in the box itself
1373 int xx1 = child->m_x;
1374 int yy1 = child->m_y;
1375 int xx2 = child->m_x + child->m_width;
1376 int yy2 = child->m_x + child->m_height;
1377
1378 // left
1379 if (((x >= xx1) && (x <= xx1+10) && (y >= yy1) && (y <= yy2)) ||
1380 // right
1381 ((x >= xx2-10) && (x <= xx2) && (y >= yy1) && (y <= yy2)) ||
1382 // top
1383 ((x >= xx1) && (x <= xx2) && (y >= yy1) && (y <= yy1+10)) ||
1384 // bottom
1385 ((x >= xx1) && (x <= xx2) && (y >= yy2-1) && (y <= yy2)))
1386 {
1387 win = child;
1388 event.m_x -= child->m_x;
1389 event.m_y -= child->m_y;
1390 break;
1391 }
1392
1393 }
1394 else
1395 {
1396 if ((child->m_wxwindow == (GtkWidget*) NULL) &&
1397 (child->m_x <= x) &&
1398 (child->m_y <= y) &&
1399 (child->m_x+child->m_width >= x) &&
1400 (child->m_y+child->m_height >= y))
1401 {
1402 win = child;
1403 event.m_x -= child->m_x;
1404 event.m_y -= child->m_y;
1405 break;
1406 }
1407 }
1408 }
1409 }
1410
1411 event.SetEventObject( win );
1412
1413 if (win->GetEventHandler()->ProcessEvent( event ))
1414 {
1415 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "button_release_event" );
1416 return TRUE;
1417 }
1418
1419 return FALSE;
1420 }
1421
1422 //-----------------------------------------------------------------------------
1423 // "motion_notify_event"
1424 //-----------------------------------------------------------------------------
1425
1426 static gint gtk_window_motion_notify_callback( GtkWidget *widget, GdkEventMotion *gdk_event, wxWindow *win )
1427 {
1428 DEBUG_MAIN_THREAD
1429
1430 if (g_isIdle)
1431 wxapp_install_idle_handler();
1432
1433 if (!win->m_hasVMT) return FALSE;
1434 if (g_blockEventsOnDrag) return FALSE;
1435 if (g_blockEventsOnScroll) return FALSE;
1436
1437 if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
1438
1439 if (gdk_event->is_hint)
1440 {
1441 int x = 0;
1442 int y = 0;
1443 GdkModifierType state;
1444 gdk_window_get_pointer(gdk_event->window, &x, &y, &state);
1445 gdk_event->x = x;
1446 gdk_event->y = y;
1447 }
1448
1449 /*
1450 printf( "OnMotion from " );
1451 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1452 printf( win->GetClassInfo()->GetClassName() );
1453 printf( ".\n" );
1454 */
1455
1456 wxMouseEvent event( wxEVT_MOTION );
1457 event.SetTimestamp( gdk_event->time );
1458 event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK);
1459 event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK);
1460 event.m_altDown = (gdk_event->state & GDK_MOD1_MASK);
1461 event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK);
1462 event.m_leftDown = (gdk_event->state & GDK_BUTTON1_MASK);
1463 event.m_middleDown = (gdk_event->state & GDK_BUTTON2_MASK);
1464 event.m_rightDown = (gdk_event->state & GDK_BUTTON3_MASK);
1465
1466 event.m_x = (wxCoord)gdk_event->x;
1467 event.m_y = (wxCoord)gdk_event->y;
1468
1469 // Some control don't have their own X window and thus cannot get
1470 // any events.
1471
1472 if (!g_captureWindow)
1473 {
1474 wxCoord x = event.m_x;
1475 wxCoord y = event.m_y;
1476 if (win->m_wxwindow)
1477 {
1478 GtkPizza *pizza = GTK_PIZZA(win->m_wxwindow);
1479 x += pizza->xoffset;
1480 y += pizza->yoffset;
1481 }
1482
1483 wxNode *node = win->GetChildren().First();
1484 while (node)
1485 {
1486 wxWindow *child = (wxWindow*)node->Data();
1487
1488 node = node->Next();
1489 if (!child->IsShown())
1490 continue;
1491
1492 if (child->m_isStaticBox)
1493 {
1494 // wxStaticBox is transparent in the box itself
1495 int xx1 = child->m_x;
1496 int yy1 = child->m_y;
1497 int xx2 = child->m_x + child->m_width;
1498 int yy2 = child->m_x + child->m_height;
1499
1500 // left
1501 if (((x >= xx1) && (x <= xx1+10) && (y >= yy1) && (y <= yy2)) ||
1502 // right
1503 ((x >= xx2-10) && (x <= xx2) && (y >= yy1) && (y <= yy2)) ||
1504 // top
1505 ((x >= xx1) && (x <= xx2) && (y >= yy1) && (y <= yy1+10)) ||
1506 // bottom
1507 ((x >= xx1) && (x <= xx2) && (y >= yy2-1) && (y <= yy2)))
1508 {
1509 win = child;
1510 event.m_x -= child->m_x;
1511 event.m_y -= child->m_y;
1512 break;
1513 }
1514
1515 }
1516 else
1517 {
1518 if ((child->m_wxwindow == (GtkWidget*) NULL) &&
1519 (child->m_x <= x) &&
1520 (child->m_y <= y) &&
1521 (child->m_x+child->m_width >= x) &&
1522 (child->m_y+child->m_height >= y))
1523 {
1524 win = child;
1525 event.m_x -= child->m_x;
1526 event.m_y -= child->m_y;
1527 break;
1528 }
1529 }
1530 }
1531 }
1532
1533 event.SetEventObject( win );
1534
1535 if (win->GetEventHandler()->ProcessEvent( event ))
1536 {
1537 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "motion_notify_event" );
1538 return TRUE;
1539 }
1540
1541 return FALSE;
1542 }
1543
1544 //-----------------------------------------------------------------------------
1545 // "focus_in_event"
1546 //-----------------------------------------------------------------------------
1547
1548 static gint gtk_window_focus_in_callback( GtkWidget *widget, GdkEvent *WXUNUSED(event), wxWindow *win )
1549 {
1550 DEBUG_MAIN_THREAD
1551
1552 if (g_isIdle)
1553 wxapp_install_idle_handler();
1554
1555 if (!win->m_hasVMT) return FALSE;
1556 if (g_blockEventsOnDrag) return FALSE;
1557
1558 switch ( g_sendActivateEvent )
1559 {
1560 case -1:
1561 // we've got focus from outside, synthtize wxActivateEvent
1562 g_sendActivateEvent = 1;
1563 break;
1564
1565 case 0:
1566 // another our window just lost focus, it was already ours before
1567 // - don't send any wxActivateEvent
1568 g_sendActivateEvent = -1;
1569 break;
1570 }
1571
1572 g_focusWindow = win;
1573
1574 /*
1575 printf( "OnSetFocus from " );
1576 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1577 printf( win->GetClassInfo()->GetClassName() );
1578 printf( " " );
1579 printf( WXSTRINGCAST win->GetLabel() );
1580 printf( ".\n" );
1581 */
1582
1583 wxPanel *panel = wxDynamicCast(win->GetParent(), wxPanel);
1584 if (panel)
1585 {
1586 panel->SetLastFocus(win);
1587 }
1588
1589 #ifdef HAVE_XIM
1590 if (win->m_ic)
1591 gdk_im_begin(win->m_ic, win->m_wxwindow->window);
1592 #endif
1593
1594 #ifdef wxUSE_CARET
1595 // caret needs to be informed about focus change
1596 wxCaret *caret = win->GetCaret();
1597 if ( caret )
1598 {
1599 caret->OnSetFocus();
1600 }
1601 #endif // wxUSE_CARET
1602
1603 if (win->IsTopLevel())
1604 {
1605 wxActivateEvent event( wxEVT_ACTIVATE, TRUE, win->GetId() );
1606 event.SetEventObject( win );
1607
1608 // ignore return value
1609 win->GetEventHandler()->ProcessEvent( event );
1610 }
1611
1612 wxFocusEvent event( wxEVT_SET_FOCUS, win->GetId() );
1613 event.SetEventObject( win );
1614
1615 if (win->GetEventHandler()->ProcessEvent( event ))
1616 {
1617 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "focus_in_event" );
1618 return TRUE;
1619 }
1620
1621
1622 return FALSE;
1623 }
1624
1625 //-----------------------------------------------------------------------------
1626 // "focus_out_event"
1627 //-----------------------------------------------------------------------------
1628
1629 static gint gtk_window_focus_out_callback( GtkWidget *widget, GdkEvent *WXUNUSED(event), wxWindow *win )
1630 {
1631 DEBUG_MAIN_THREAD
1632
1633 if (g_isIdle)
1634 wxapp_install_idle_handler();
1635
1636 if (!win->m_hasVMT) return FALSE;
1637 if (g_blockEventsOnDrag) return FALSE;
1638
1639 // if the focus goes out of our app alltogether, OnIdle() will send
1640 // wxActivateEvent, otherwise gtk_window_focus_in_callback() will reset
1641 // g_sendActivateEvent to -1
1642 g_sendActivateEvent = 0;
1643
1644 wxWindow *winFocus = FindFocusedChild(win);
1645 if ( winFocus )
1646 win = winFocus;
1647
1648 g_focusWindow = (wxWindow *)NULL;
1649
1650 /*
1651 printf( "OnKillFocus from " );
1652 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1653 printf( win->GetClassInfo()->GetClassName() );
1654 printf( ".\n" );
1655 */
1656
1657 #ifdef HAVE_XIM
1658 if (win->m_ic)
1659 gdk_im_end();
1660 #endif
1661
1662 #ifdef wxUSE_CARET
1663 // caret needs to be informed about focus change
1664 wxCaret *caret = win->GetCaret();
1665 if ( caret )
1666 {
1667 caret->OnKillFocus();
1668 }
1669 #endif // wxUSE_CARET
1670
1671 if (win->IsTopLevel())
1672 {
1673 wxActivateEvent event( wxEVT_ACTIVATE, FALSE, win->GetId() );
1674 event.SetEventObject( win );
1675
1676 // ignore return value
1677 win->GetEventHandler()->ProcessEvent( event );
1678 }
1679
1680 wxFocusEvent event( wxEVT_KILL_FOCUS, win->GetId() );
1681 event.SetEventObject( win );
1682
1683 if (win->GetEventHandler()->ProcessEvent( event ))
1684 {
1685 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "focus_out_event" );
1686 return TRUE;
1687 }
1688
1689 return FALSE;
1690 }
1691
1692 //-----------------------------------------------------------------------------
1693 // "enter_notify_event"
1694 //-----------------------------------------------------------------------------
1695
1696 static gint gtk_window_enter_callback( GtkWidget *widget, GdkEventCrossing *gdk_event, wxWindow *win )
1697 {
1698 DEBUG_MAIN_THREAD
1699
1700 if (g_isIdle)
1701 wxapp_install_idle_handler();
1702
1703 if (!win->m_hasVMT) return FALSE;
1704 if (g_blockEventsOnDrag) return FALSE;
1705
1706 if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
1707
1708 wxMouseEvent event( wxEVT_ENTER_WINDOW );
1709 #if (GTK_MINOR_VERSION > 0)
1710 event.SetTimestamp( gdk_event->time );
1711 #endif
1712 event.SetEventObject( win );
1713
1714 int x = 0;
1715 int y = 0;
1716 GdkModifierType state = (GdkModifierType)0;
1717
1718 gdk_window_get_pointer( widget->window, &x, &y, &state );
1719
1720 event.m_shiftDown = (state & GDK_SHIFT_MASK);
1721 event.m_controlDown = (state & GDK_CONTROL_MASK);
1722 event.m_altDown = (state & GDK_MOD1_MASK);
1723 event.m_metaDown = (state & GDK_MOD2_MASK);
1724 event.m_leftDown = (state & GDK_BUTTON1_MASK);
1725 event.m_middleDown = (state & GDK_BUTTON2_MASK);
1726 event.m_rightDown = (state & GDK_BUTTON3_MASK);
1727
1728 event.m_x = x;
1729 event.m_y = y;
1730
1731 if (win->GetEventHandler()->ProcessEvent( event ))
1732 {
1733 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "enter_notify_event" );
1734 return TRUE;
1735 }
1736
1737 return FALSE;
1738 }
1739
1740 //-----------------------------------------------------------------------------
1741 // "leave_notify_event"
1742 //-----------------------------------------------------------------------------
1743
1744 static gint gtk_window_leave_callback( GtkWidget *widget, GdkEventCrossing *gdk_event, wxWindow *win )
1745 {
1746 DEBUG_MAIN_THREAD
1747
1748 if (g_isIdle)
1749 wxapp_install_idle_handler();
1750
1751 if (!win->m_hasVMT) return FALSE;
1752 if (g_blockEventsOnDrag) return FALSE;
1753
1754 if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
1755
1756 wxMouseEvent event( wxEVT_LEAVE_WINDOW );
1757 #if (GTK_MINOR_VERSION > 0)
1758 event.SetTimestamp( gdk_event->time );
1759 #endif
1760 event.SetEventObject( win );
1761
1762 int x = 0;
1763 int y = 0;
1764 GdkModifierType state = (GdkModifierType)0;
1765
1766 gdk_window_get_pointer( widget->window, &x, &y, &state );
1767
1768 event.m_shiftDown = (state & GDK_SHIFT_MASK);
1769 event.m_controlDown = (state & GDK_CONTROL_MASK);
1770 event.m_altDown = (state & GDK_MOD1_MASK);
1771 event.m_metaDown = (state & GDK_MOD2_MASK);
1772 event.m_leftDown = (state & GDK_BUTTON1_MASK);
1773 event.m_middleDown = (state & GDK_BUTTON2_MASK);
1774 event.m_rightDown = (state & GDK_BUTTON3_MASK);
1775
1776 event.m_x = x;
1777 event.m_y = y;
1778
1779 if (win->GetEventHandler()->ProcessEvent( event ))
1780 {
1781 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "leave_notify_event" );
1782 return TRUE;
1783 }
1784
1785 return FALSE;
1786 }
1787
1788 //-----------------------------------------------------------------------------
1789 // "value_changed" from m_vAdjust
1790 //-----------------------------------------------------------------------------
1791
1792 static void gtk_window_vscroll_callback( GtkAdjustment *adjust, wxWindow *win )
1793 {
1794 DEBUG_MAIN_THREAD
1795
1796 if (g_isIdle)
1797 wxapp_install_idle_handler();
1798
1799 if (g_blockEventsOnDrag) return;
1800
1801 if (!win->m_hasVMT) return;
1802
1803 float diff = adjust->value - win->m_oldVerticalPos;
1804 if (fabs(diff) < 0.2) return;
1805
1806 win->m_oldVerticalPos = adjust->value;
1807
1808 GtkScrolledWindow *scrolledWindow = GTK_SCROLLED_WINDOW(win->m_widget);
1809 GtkRange *range = GTK_RANGE( scrolledWindow->vscrollbar );
1810
1811 wxEventType command = wxEVT_SCROLLWIN_THUMBTRACK;
1812 if (range->scroll_type == GTK_SCROLL_STEP_BACKWARD) command = wxEVT_SCROLLWIN_LINEUP;
1813 else if (range->scroll_type == GTK_SCROLL_STEP_FORWARD) command = wxEVT_SCROLLWIN_LINEDOWN;
1814 else if (range->scroll_type == GTK_SCROLL_PAGE_BACKWARD) command = wxEVT_SCROLLWIN_PAGEUP;
1815 else if (range->scroll_type == GTK_SCROLL_PAGE_FORWARD) command = wxEVT_SCROLLWIN_PAGEDOWN;
1816
1817 int value = (int)(adjust->value+0.5);
1818
1819 wxScrollWinEvent event( command, value, wxVERTICAL );
1820 event.SetEventObject( win );
1821 win->GetEventHandler()->ProcessEvent( event );
1822 }
1823
1824 //-----------------------------------------------------------------------------
1825 // "value_changed" from m_hAdjust
1826 //-----------------------------------------------------------------------------
1827
1828 static void gtk_window_hscroll_callback( GtkAdjustment *adjust, wxWindow *win )
1829 {
1830 DEBUG_MAIN_THREAD
1831
1832 if (g_isIdle)
1833 wxapp_install_idle_handler();
1834
1835 if (g_blockEventsOnDrag) return;
1836 if (!win->m_hasVMT) return;
1837
1838 float diff = adjust->value - win->m_oldHorizontalPos;
1839 if (fabs(diff) < 0.2) return;
1840
1841 win->m_oldHorizontalPos = adjust->value;
1842
1843 GtkScrolledWindow *scrolledWindow = GTK_SCROLLED_WINDOW(win->m_widget);
1844 GtkRange *range = GTK_RANGE( scrolledWindow->hscrollbar );
1845
1846 wxEventType command = wxEVT_SCROLLWIN_THUMBTRACK;
1847 if (range->scroll_type == GTK_SCROLL_STEP_BACKWARD) command = wxEVT_SCROLLWIN_LINEUP;
1848 else if (range->scroll_type == GTK_SCROLL_STEP_FORWARD) command = wxEVT_SCROLLWIN_LINEDOWN;
1849 else if (range->scroll_type == GTK_SCROLL_PAGE_BACKWARD) command = wxEVT_SCROLLWIN_PAGEUP;
1850 else if (range->scroll_type == GTK_SCROLL_PAGE_FORWARD) command = wxEVT_SCROLLWIN_PAGEDOWN;
1851
1852 int value = (int)(adjust->value+0.5);
1853
1854 wxScrollWinEvent event( command, value, wxHORIZONTAL );
1855 event.SetEventObject( win );
1856 win->GetEventHandler()->ProcessEvent( event );
1857 }
1858
1859 //-----------------------------------------------------------------------------
1860 // "button_press_event" from scrollbar
1861 //-----------------------------------------------------------------------------
1862
1863 static gint gtk_scrollbar_button_press_callback( GtkRange *widget,
1864 GdkEventButton *gdk_event,
1865 wxWindow *win)
1866 {
1867 DEBUG_MAIN_THREAD
1868
1869 if (g_isIdle)
1870 wxapp_install_idle_handler();
1871
1872
1873 g_blockEventsOnScroll = TRUE;
1874 win->m_isScrolling = (gdk_event->window == widget->slider);
1875
1876 return FALSE;
1877 }
1878
1879 //-----------------------------------------------------------------------------
1880 // "button_release_event" from scrollbar
1881 //-----------------------------------------------------------------------------
1882
1883 static gint gtk_scrollbar_button_release_callback( GtkRange *widget,
1884 GdkEventButton *WXUNUSED(gdk_event),
1885 wxWindow *win)
1886 {
1887 DEBUG_MAIN_THREAD
1888
1889 // don't test here as we can release the mouse while being over
1890 // a different window than the slider
1891 //
1892 // if (gdk_event->window != widget->slider) return FALSE;
1893
1894 g_blockEventsOnScroll = FALSE;
1895
1896 if (win->m_isScrolling)
1897 {
1898 wxEventType command = wxEVT_SCROLLWIN_THUMBRELEASE;
1899 int value = -1;
1900 int dir = -1;
1901
1902 GtkScrolledWindow *scrolledWindow = GTK_SCROLLED_WINDOW(win->m_widget);
1903 if (widget == GTK_RANGE(scrolledWindow->hscrollbar))
1904 {
1905 value = (int)(win->m_hAdjust->value+0.5);
1906 dir = wxHORIZONTAL;
1907 }
1908 if (widget == GTK_RANGE(scrolledWindow->vscrollbar))
1909 {
1910 value = (int)(win->m_vAdjust->value+0.5);
1911 dir = wxVERTICAL;
1912 }
1913
1914 wxScrollWinEvent event( command, value, dir );
1915 event.SetEventObject( win );
1916 win->GetEventHandler()->ProcessEvent( event );
1917 }
1918
1919 win->m_isScrolling = FALSE;
1920
1921 return FALSE;
1922 }
1923
1924 // ----------------------------------------------------------------------------
1925 // this wxWindowBase function is implemented here (in platform-specific file)
1926 // because it is static and so couldn't be made virtual
1927 // ----------------------------------------------------------------------------
1928
1929 wxWindow *wxWindowBase::FindFocus()
1930 {
1931 return g_focusWindow;
1932 }
1933
1934 //-----------------------------------------------------------------------------
1935 // "realize" from m_widget
1936 //-----------------------------------------------------------------------------
1937
1938 /* We cannot set colours and fonts before the widget has
1939 been realized, so we do this directly after realization. */
1940
1941 static gint
1942 gtk_window_realized_callback( GtkWidget *WXUNUSED(m_widget), wxWindow *win )
1943 {
1944 DEBUG_MAIN_THREAD
1945
1946 if (g_isIdle)
1947 wxapp_install_idle_handler();
1948
1949 if (win->m_delayedBackgroundColour)
1950 win->SetBackgroundColour( win->GetBackgroundColour() );
1951
1952 if (win->m_delayedForegroundColour)
1953 win->SetForegroundColour( win->GetForegroundColour() );
1954
1955 wxWindowCreateEvent event( win );
1956 event.SetEventObject( win );
1957 win->GetEventHandler()->ProcessEvent( event );
1958
1959 return FALSE;
1960 }
1961
1962 //-----------------------------------------------------------------------------
1963 // "size_allocate"
1964 //-----------------------------------------------------------------------------
1965
1966 static
1967 void gtk_window_size_callback( GtkWidget *WXUNUSED(widget),
1968 GtkAllocation *WXUNUSED(alloc),
1969 wxWindow *win )
1970 {
1971 if (g_isIdle)
1972 wxapp_install_idle_handler();
1973
1974 if (!win->m_hasScrolling) return;
1975
1976 int client_width = 0;
1977 int client_height = 0;
1978 win->GetClientSize( &client_width, &client_height );
1979 if ((client_width == win->m_oldClientWidth) && (client_height == win->m_oldClientHeight))
1980 return;
1981
1982 win->m_oldClientWidth = client_width;
1983 win->m_oldClientHeight = client_height;
1984
1985 if (!win->m_nativeSizeEvent)
1986 {
1987 wxSizeEvent event( win->GetSize(), win->GetId() );
1988 event.SetEventObject( win );
1989 win->GetEventHandler()->ProcessEvent( event );
1990 }
1991 }
1992
1993
1994 #ifdef HAVE_XIM
1995 #define WXUNUSED_UNLESS_XIM(param) param
1996 #else
1997 #define WXUNUSED_UNLESS_XIM(param) WXUNUSED(param)
1998 #endif
1999
2000 /* Resize XIM window */
2001
2002 static
2003 void gtk_wxwindow_size_callback( GtkWidget* WXUNUSED_UNLESS_XIM(widget),
2004 GtkAllocation* WXUNUSED_UNLESS_XIM(alloc),
2005 wxWindow* WXUNUSED_UNLESS_XIM(win) )
2006 {
2007 if (g_isIdle)
2008 wxapp_install_idle_handler();
2009
2010 #ifdef HAVE_XIM
2011 if (!win->m_ic)
2012 return;
2013
2014 if (gdk_ic_get_style (win->m_ic) & GDK_IM_PREEDIT_POSITION)
2015 {
2016 gint width, height;
2017
2018 gdk_window_get_size (widget->window, &width, &height);
2019 win->m_icattr->preedit_area.width = width;
2020 win->m_icattr->preedit_area.height = height;
2021 gdk_ic_set_attr (win->m_ic, win->m_icattr, GDK_IC_PREEDIT_AREA);
2022 }
2023 #endif // HAVE_XIM
2024 }
2025
2026 //-----------------------------------------------------------------------------
2027 // "realize" from m_wxwindow
2028 //-----------------------------------------------------------------------------
2029
2030 /* Initialize XIM support */
2031
2032 static gint
2033 gtk_wxwindow_realized_callback( GtkWidget * WXUNUSED_UNLESS_XIM(widget),
2034 wxWindow * WXUNUSED_UNLESS_XIM(win) )
2035 {
2036 if (g_isIdle)
2037 wxapp_install_idle_handler();
2038
2039 #ifdef HAVE_XIM
2040 if (win->m_ic) return FALSE;
2041 if (!widget) return FALSE;
2042 if (!gdk_im_ready()) return FALSE;
2043
2044 win->m_icattr = gdk_ic_attr_new();
2045 if (!win->m_icattr) return FALSE;
2046
2047 gint width, height;
2048 GdkEventMask mask;
2049 GdkColormap *colormap;
2050 GdkICAttr *attr = win->m_icattr;
2051 unsigned attrmask = GDK_IC_ALL_REQ;
2052 GdkIMStyle style;
2053 GdkIMStyle supported_style = (GdkIMStyle)
2054 (GDK_IM_PREEDIT_NONE |
2055 GDK_IM_PREEDIT_NOTHING |
2056 GDK_IM_PREEDIT_POSITION |
2057 GDK_IM_STATUS_NONE |
2058 GDK_IM_STATUS_NOTHING);
2059
2060 if (widget->style && widget->style->font->type != GDK_FONT_FONTSET)
2061 supported_style = (GdkIMStyle)(supported_style & ~GDK_IM_PREEDIT_POSITION);
2062
2063 attr->style = style = gdk_im_decide_style (supported_style);
2064 attr->client_window = widget->window;
2065
2066 if ((colormap = gtk_widget_get_colormap (widget)) !=
2067 gtk_widget_get_default_colormap ())
2068 {
2069 attrmask |= GDK_IC_PREEDIT_COLORMAP;
2070 attr->preedit_colormap = colormap;
2071 }
2072
2073 attrmask |= GDK_IC_PREEDIT_FOREGROUND;
2074 attrmask |= GDK_IC_PREEDIT_BACKGROUND;
2075 attr->preedit_foreground = widget->style->fg[GTK_STATE_NORMAL];
2076 attr->preedit_background = widget->style->base[GTK_STATE_NORMAL];
2077
2078 switch (style & GDK_IM_PREEDIT_MASK)
2079 {
2080 case GDK_IM_PREEDIT_POSITION:
2081 if (widget->style && widget->style->font->type != GDK_FONT_FONTSET)
2082 {
2083 g_warning ("over-the-spot style requires fontset");
2084 break;
2085 }
2086
2087 gdk_window_get_size (widget->window, &width, &height);
2088
2089 attrmask |= GDK_IC_PREEDIT_POSITION_REQ;
2090 attr->spot_location.x = 0;
2091 attr->spot_location.y = height;
2092 attr->preedit_area.x = 0;
2093 attr->preedit_area.y = 0;
2094 attr->preedit_area.width = width;
2095 attr->preedit_area.height = height;
2096 attr->preedit_fontset = widget->style->font;
2097
2098 break;
2099 }
2100
2101 win->m_ic = gdk_ic_new (attr, (GdkICAttributesType)attrmask);
2102
2103 if (win->m_ic == NULL)
2104 g_warning ("Can't create input context.");
2105 else
2106 {
2107 mask = gdk_window_get_events (widget->window);
2108 mask = (GdkEventMask)(mask | gdk_ic_get_events (win->m_ic));
2109 gdk_window_set_events (widget->window, mask);
2110
2111 if (GTK_WIDGET_HAS_FOCUS(widget))
2112 gdk_im_begin (win->m_ic, widget->window);
2113 }
2114 #endif
2115
2116 return FALSE;
2117 }
2118
2119 //-----------------------------------------------------------------------------
2120 // InsertChild for wxWindow.
2121 //-----------------------------------------------------------------------------
2122
2123 /* Callback for wxWindow. This very strange beast has to be used because
2124 * C++ has no virtual methods in a constructor. We have to emulate a
2125 * virtual function here as wxNotebook requires a different way to insert
2126 * a child in it. I had opted for creating a wxNotebookPage window class
2127 * which would have made this superfluous (such in the MDI window system),
2128 * but no-one was listening to me... */
2129
2130 static void wxInsertChildInWindow( wxWindow* parent, wxWindow* child )
2131 {
2132 /* the window might have been scrolled already, do we
2133 have to adapt the position */
2134 GtkPizza *pizza = GTK_PIZZA(parent->m_wxwindow);
2135 child->m_x += pizza->xoffset;
2136 child->m_y += pizza->yoffset;
2137
2138 gtk_pizza_put( GTK_PIZZA(parent->m_wxwindow),
2139 GTK_WIDGET(child->m_widget),
2140 child->m_x,
2141 child->m_y,
2142 child->m_width,
2143 child->m_height );
2144 }
2145
2146 //-----------------------------------------------------------------------------
2147 // global functions
2148 //-----------------------------------------------------------------------------
2149
2150 wxWindow* wxGetActiveWindow()
2151 {
2152 return g_focusWindow;
2153 }
2154
2155 //-----------------------------------------------------------------------------
2156 // wxWindow
2157 //-----------------------------------------------------------------------------
2158
2159 IMPLEMENT_DYNAMIC_CLASS(wxWindow, wxWindowBase)
2160
2161 void wxWindow::Init()
2162 {
2163 // common init
2164 InitBase();
2165
2166 // GTK specific
2167 m_widget = (GtkWidget *) NULL;
2168 m_wxwindow = (GtkWidget *) NULL;
2169
2170 // position/size
2171 m_x = 0;
2172 m_y = 0;
2173 m_width = 0;
2174 m_height = 0;
2175
2176 m_sizeSet = FALSE;
2177 m_hasVMT = FALSE;
2178 m_needParent = TRUE;
2179 m_isBeingDeleted = FALSE;
2180
2181 m_noExpose = FALSE;
2182 m_nativeSizeEvent = FALSE;
2183
2184 m_hasScrolling = FALSE;
2185 m_isScrolling = FALSE;
2186
2187 m_hAdjust = (GtkAdjustment*) NULL;
2188 m_vAdjust = (GtkAdjustment*) NULL;
2189 m_oldHorizontalPos = 0.0;
2190 m_oldVerticalPos = 0.0;
2191
2192 m_resizing = FALSE;
2193 m_widgetStyle = (GtkStyle*) NULL;
2194
2195 m_insertCallback = (wxInsertChildFunction) NULL;
2196
2197 m_isStaticBox = FALSE;
2198 m_isRadioButton = FALSE;
2199 m_isFrame = FALSE;
2200 m_acceptsFocus = FALSE;
2201
2202 m_clipPaintRegion = FALSE;
2203
2204 m_cursor = *wxSTANDARD_CURSOR;
2205
2206 m_delayedForegroundColour = FALSE;
2207 m_delayedBackgroundColour = FALSE;
2208
2209 #ifdef HAVE_XIM
2210 m_ic = (GdkIC*) NULL;
2211 m_icattr = (GdkICAttr*) NULL;
2212 #endif
2213 }
2214
2215 wxWindow::wxWindow()
2216 {
2217 Init();
2218 }
2219
2220 wxWindow::wxWindow( wxWindow *parent, wxWindowID id,
2221 const wxPoint &pos, const wxSize &size,
2222 long style, const wxString &name )
2223 {
2224 Init();
2225
2226 Create( parent, id, pos, size, style, name );
2227 }
2228
2229 bool wxWindow::Create( wxWindow *parent, wxWindowID id,
2230 const wxPoint &pos, const wxSize &size,
2231 long style, const wxString &name )
2232 {
2233 if (!PreCreation( parent, pos, size ) ||
2234 !CreateBase( parent, id, pos, size, style, wxDefaultValidator, name ))
2235 {
2236 wxFAIL_MSG( wxT("wxWindow creation failed") );
2237 return FALSE;
2238 }
2239
2240 m_insertCallback = wxInsertChildInWindow;
2241
2242 m_widget = gtk_scrolled_window_new( (GtkAdjustment *) NULL, (GtkAdjustment *) NULL );
2243 GTK_WIDGET_UNSET_FLAGS( m_widget, GTK_CAN_FOCUS );
2244
2245 GtkScrolledWindow *scrolledWindow = GTK_SCROLLED_WINDOW(m_widget);
2246
2247 GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget) );
2248 scroll_class->scrollbar_spacing = 0;
2249
2250 gtk_scrolled_window_set_policy( scrolledWindow, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC );
2251
2252 m_hAdjust = gtk_range_get_adjustment( GTK_RANGE(scrolledWindow->hscrollbar) );
2253 m_vAdjust = gtk_range_get_adjustment( GTK_RANGE(scrolledWindow->vscrollbar) );
2254
2255 m_wxwindow = gtk_pizza_new();
2256
2257 gtk_container_add( GTK_CONTAINER(m_widget), m_wxwindow );
2258
2259 #if (GTK_MINOR_VERSION > 0)
2260 GtkPizza *pizza = GTK_PIZZA(m_wxwindow);
2261
2262 if (HasFlag(wxRAISED_BORDER))
2263 {
2264 gtk_pizza_set_shadow_type( pizza, GTK_MYSHADOW_OUT );
2265 }
2266 else if (HasFlag(wxSUNKEN_BORDER))
2267 {
2268 gtk_pizza_set_shadow_type( pizza, GTK_MYSHADOW_IN );
2269 }
2270 else if (HasFlag(wxSIMPLE_BORDER))
2271 {
2272 gtk_pizza_set_shadow_type( pizza, GTK_MYSHADOW_THIN );
2273 }
2274 else
2275 {
2276 gtk_pizza_set_shadow_type( pizza, GTK_MYSHADOW_NONE );
2277 }
2278 #else // GTK_MINOR_VERSION == 0
2279 GtkViewport *viewport = GTK_VIEWPORT(scrolledWindow->viewport);
2280
2281 if (HasFlag(wxRAISED_BORDER))
2282 {
2283 gtk_viewport_set_shadow_type( viewport, GTK_SHADOW_OUT );
2284 }
2285 else if (HasFlag(wxSUNKEN_BORDER))
2286 {
2287 gtk_viewport_set_shadow_type( viewport, GTK_SHADOW_IN );
2288 }
2289 else
2290 {
2291 gtk_viewport_set_shadow_type( viewport, GTK_SHADOW_NONE );
2292 }
2293 #endif // GTK_MINOR_VERSION
2294
2295 GTK_WIDGET_SET_FLAGS( m_wxwindow, GTK_CAN_FOCUS );
2296 m_acceptsFocus = TRUE;
2297
2298 #if (GTK_MINOR_VERSION == 0)
2299 // shut the viewport up
2300 gtk_viewport_set_hadjustment( viewport, (GtkAdjustment*) gtk_adjustment_new( 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) );
2301 gtk_viewport_set_vadjustment( viewport, (GtkAdjustment*) gtk_adjustment_new( 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) );
2302 #endif // GTK_MINOR_VERSION == 0
2303
2304 // I _really_ don't want scrollbars in the beginning
2305 m_vAdjust->lower = 0.0;
2306 m_vAdjust->upper = 1.0;
2307 m_vAdjust->value = 0.0;
2308 m_vAdjust->step_increment = 1.0;
2309 m_vAdjust->page_increment = 1.0;
2310 m_vAdjust->page_size = 5.0;
2311 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust), "changed" );
2312 m_hAdjust->lower = 0.0;
2313 m_hAdjust->upper = 1.0;
2314 m_hAdjust->value = 0.0;
2315 m_hAdjust->step_increment = 1.0;
2316 m_hAdjust->page_increment = 1.0;
2317 m_hAdjust->page_size = 5.0;
2318 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust), "changed" );
2319
2320 // these handlers block mouse events to any window during scrolling such as
2321 // motion events and prevent GTK and wxWindows from fighting over where the
2322 // slider should be
2323
2324 gtk_signal_connect( GTK_OBJECT(scrolledWindow->vscrollbar), "button_press_event",
2325 (GtkSignalFunc)gtk_scrollbar_button_press_callback, (gpointer) this );
2326
2327 gtk_signal_connect( GTK_OBJECT(scrolledWindow->hscrollbar), "button_press_event",
2328 (GtkSignalFunc)gtk_scrollbar_button_press_callback, (gpointer) this );
2329
2330 gtk_signal_connect( GTK_OBJECT(scrolledWindow->vscrollbar), "button_release_event",
2331 (GtkSignalFunc)gtk_scrollbar_button_release_callback, (gpointer) this );
2332
2333 gtk_signal_connect( GTK_OBJECT(scrolledWindow->hscrollbar), "button_release_event",
2334 (GtkSignalFunc)gtk_scrollbar_button_release_callback, (gpointer) this );
2335
2336 // these handlers get notified when screen updates are required either when
2337 // scrolling or when the window size (and therefore scrollbar configuration)
2338 // has changed
2339
2340 gtk_signal_connect( GTK_OBJECT(m_hAdjust), "value_changed",
2341 (GtkSignalFunc) gtk_window_hscroll_callback, (gpointer) this );
2342 gtk_signal_connect( GTK_OBJECT(m_vAdjust), "value_changed",
2343 (GtkSignalFunc) gtk_window_vscroll_callback, (gpointer) this );
2344
2345 gtk_widget_show( m_wxwindow );
2346
2347 if (m_parent)
2348 m_parent->DoAddChild( this );
2349
2350 PostCreation();
2351
2352 Show( TRUE );
2353
2354 return TRUE;
2355 }
2356
2357 wxWindow::~wxWindow()
2358 {
2359 if (g_focusWindow == this)
2360 g_focusWindow = NULL;
2361
2362 m_isBeingDeleted = TRUE;
2363 m_hasVMT = FALSE;
2364
2365 if (m_widget)
2366 Show( FALSE );
2367
2368 DestroyChildren();
2369
2370 if (m_parent)
2371 m_parent->RemoveChild( this );
2372
2373 #ifdef HAVE_XIM
2374 if (m_ic)
2375 gdk_ic_destroy (m_ic);
2376 if (m_icattr)
2377 gdk_ic_attr_destroy (m_icattr);
2378 #endif
2379
2380 if (m_widgetStyle)
2381 {
2382 #if DISABLE_STYLE_IF_BROKEN_THEME
2383 // don't delete if it's a pixmap theme style
2384 if (!m_widgetStyle->engine_data)
2385 gtk_style_unref( m_widgetStyle );
2386 #endif
2387 m_widgetStyle = (GtkStyle*) NULL;
2388 }
2389
2390 if (m_wxwindow)
2391 {
2392 gtk_widget_destroy( m_wxwindow );
2393 m_wxwindow = (GtkWidget*) NULL;
2394 }
2395
2396 if (m_widget)
2397 {
2398 gtk_widget_destroy( m_widget );
2399 m_widget = (GtkWidget*) NULL;
2400 }
2401 }
2402
2403 bool wxWindow::PreCreation( wxWindow *parent, const wxPoint &pos, const wxSize &size )
2404 {
2405 wxCHECK_MSG( !m_needParent || parent, FALSE, wxT("Need complete parent.") );
2406
2407 /* this turns -1 into 20 so that a minimal window is
2408 visible even although -1,-1 has been given as the
2409 size of the window. the same trick is used in other
2410 ports and should make debugging easier */
2411 m_width = WidthDefault(size.x);
2412 m_height = HeightDefault(size.y);
2413
2414 m_x = (int)pos.x;
2415 m_y = (int)pos.y;
2416
2417 /* some reasonable defaults */
2418 if (!parent)
2419 {
2420 if (m_x == -1)
2421 {
2422 m_x = (gdk_screen_width () - m_width) / 2;
2423 if (m_x < 10) m_x = 10;
2424 }
2425 if (m_y == -1)
2426 {
2427 m_y = (gdk_screen_height () - m_height) / 2;
2428 if (m_y < 10) m_y = 10;
2429 }
2430 }
2431
2432 return TRUE;
2433 }
2434
2435 void wxWindow::PostCreation()
2436 {
2437 wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
2438
2439 if (m_wxwindow)
2440 {
2441 if (!m_noExpose)
2442 {
2443 /* these get reported to wxWindows -> wxPaintEvent */
2444
2445 gtk_pizza_set_external( GTK_PIZZA(m_wxwindow), TRUE );
2446
2447 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "expose_event",
2448 GTK_SIGNAL_FUNC(gtk_window_expose_callback), (gpointer)this );
2449
2450 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "draw",
2451 GTK_SIGNAL_FUNC(gtk_window_draw_callback), (gpointer)this );
2452
2453 if (HasFlag(wxNO_FULL_REPAINT_ON_RESIZE))
2454 {
2455 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "event",
2456 GTK_SIGNAL_FUNC(gtk_window_event_event_callback), (gpointer)this );
2457 }
2458 }
2459
2460 #if (GTK_MINOR_VERSION > 0)
2461 /* these are called when the "sunken" or "raised" borders are drawn */
2462 gtk_signal_connect( GTK_OBJECT(m_widget), "expose_event",
2463 GTK_SIGNAL_FUNC(gtk_window_own_expose_callback), (gpointer)this );
2464
2465 gtk_signal_connect( GTK_OBJECT(m_widget), "draw",
2466 GTK_SIGNAL_FUNC(gtk_window_own_draw_callback), (gpointer)this );
2467 #endif
2468 }
2469
2470 if (m_wxwindow && m_needParent)
2471 {
2472 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "focus_in_event",
2473 GTK_SIGNAL_FUNC(gtk_window_focus_in_callback), (gpointer)this );
2474
2475 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "focus_out_event",
2476 GTK_SIGNAL_FUNC(gtk_window_focus_out_callback), (gpointer)this );
2477 }
2478 else
2479 {
2480 // For dialogs and frames, we are interested mainly in
2481 // m_widget's focus.
2482
2483 gtk_signal_connect( GTK_OBJECT(m_widget), "focus_in_event",
2484 GTK_SIGNAL_FUNC(gtk_window_focus_in_callback), (gpointer)this );
2485
2486 gtk_signal_connect( GTK_OBJECT(m_widget), "focus_out_event",
2487 GTK_SIGNAL_FUNC(gtk_window_focus_out_callback), (gpointer)this );
2488 }
2489
2490 GtkWidget *connect_widget = GetConnectWidget();
2491
2492 ConnectWidget( connect_widget );
2493
2494 /* We cannot set colours, fonts and cursors before the widget has
2495 been realized, so we do this directly after realization */
2496 gtk_signal_connect( GTK_OBJECT(connect_widget), "realize",
2497 GTK_SIGNAL_FUNC(gtk_window_realized_callback), (gpointer) this );
2498
2499 if (m_wxwindow)
2500 {
2501 // Catch native resize events
2502 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "size_allocate",
2503 GTK_SIGNAL_FUNC(gtk_window_size_callback), (gpointer)this );
2504
2505 // Initialize XIM support
2506 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "realize",
2507 GTK_SIGNAL_FUNC(gtk_wxwindow_realized_callback), (gpointer) this );
2508
2509 // And resize XIM window
2510 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "size_allocate",
2511 GTK_SIGNAL_FUNC(gtk_wxwindow_size_callback), (gpointer)this );
2512 }
2513
2514 if (!GTK_IS_COMBO(m_widget))
2515 {
2516 // This is needed if we want to add our windows into native
2517 // GTK control, such as the toolbar. With this callback, the
2518 // toolbar gets to know the correct size (the one set by the
2519 // programmer). Sadly, it misbehaves for wxComboBox. FIXME
2520 // when moving to GTK 2.0.
2521 gtk_signal_connect( GTK_OBJECT(m_widget), "size_request",
2522 GTK_SIGNAL_FUNC(gtk_window_size_request_callback), (gpointer) this );
2523 }
2524
2525 m_hasVMT = TRUE;
2526 }
2527
2528 void wxWindow::ConnectWidget( GtkWidget *widget )
2529 {
2530 gtk_signal_connect( GTK_OBJECT(widget), "key_press_event",
2531 GTK_SIGNAL_FUNC(gtk_window_key_press_callback), (gpointer)this );
2532
2533 gtk_signal_connect( GTK_OBJECT(widget), "key_release_event",
2534 GTK_SIGNAL_FUNC(gtk_window_key_release_callback), (gpointer)this );
2535
2536 gtk_signal_connect( GTK_OBJECT(widget), "button_press_event",
2537 GTK_SIGNAL_FUNC(gtk_window_button_press_callback), (gpointer)this );
2538
2539 gtk_signal_connect( GTK_OBJECT(widget), "button_release_event",
2540 GTK_SIGNAL_FUNC(gtk_window_button_release_callback), (gpointer)this );
2541
2542 gtk_signal_connect( GTK_OBJECT(widget), "motion_notify_event",
2543 GTK_SIGNAL_FUNC(gtk_window_motion_notify_callback), (gpointer)this );
2544
2545 gtk_signal_connect( GTK_OBJECT(widget), "enter_notify_event",
2546 GTK_SIGNAL_FUNC(gtk_window_enter_callback), (gpointer)this );
2547
2548 gtk_signal_connect( GTK_OBJECT(widget), "leave_notify_event",
2549 GTK_SIGNAL_FUNC(gtk_window_leave_callback), (gpointer)this );
2550 }
2551
2552 bool wxWindow::Destroy()
2553 {
2554 wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
2555
2556 m_hasVMT = FALSE;
2557
2558 return wxWindowBase::Destroy();
2559 }
2560
2561 void wxWindow::DoMoveWindow(int x, int y, int width, int height)
2562 {
2563 gtk_pizza_set_size( GTK_PIZZA(m_parent->m_wxwindow), m_widget, x, y, width, height );
2564 }
2565
2566 void wxWindow::DoSetSize( int x, int y, int width, int height, int sizeFlags )
2567 {
2568 wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
2569 wxASSERT_MSG( (m_parent != NULL), wxT("wxWindow::SetSize requires parent.\n") );
2570
2571 if (m_resizing) return; /* I don't like recursions */
2572 m_resizing = TRUE;
2573
2574 if (m_parent->m_wxwindow == NULL) /* i.e. wxNotebook */
2575 {
2576 /* don't set the size for children of wxNotebook, just take the values. */
2577 m_x = x;
2578 m_y = y;
2579 m_width = width;
2580 m_height = height;
2581 }
2582 else
2583 {
2584 GtkPizza *pizza = GTK_PIZZA(m_parent->m_wxwindow);
2585
2586 if ((sizeFlags & wxSIZE_ALLOW_MINUS_ONE) == 0)
2587 {
2588 if (x != -1) m_x = x + pizza->xoffset;
2589 if (y != -1) m_y = y + pizza->yoffset;
2590 if (width != -1) m_width = width;
2591 if (height != -1) m_height = height;
2592 }
2593 else
2594 {
2595 m_x = x + pizza->xoffset;
2596 m_y = y + pizza->yoffset;
2597 m_width = width;
2598 m_height = height;
2599 }
2600
2601 if ((sizeFlags & wxSIZE_AUTO_WIDTH) == wxSIZE_AUTO_WIDTH)
2602 {
2603 if (width == -1) m_width = 80;
2604 }
2605
2606 if ((sizeFlags & wxSIZE_AUTO_HEIGHT) == wxSIZE_AUTO_HEIGHT)
2607 {
2608 if (height == -1) m_height = 26;
2609 }
2610
2611 if ((m_minWidth != -1) && (m_width < m_minWidth)) m_width = m_minWidth;
2612 if ((m_minHeight != -1) && (m_height < m_minHeight)) m_height = m_minHeight;
2613 if ((m_maxWidth != -1) && (m_width > m_maxWidth)) m_width = m_maxWidth;
2614 if ((m_maxHeight != -1) && (m_height > m_maxHeight)) m_height = m_maxHeight;
2615
2616 int border = 0;
2617 int bottom_border = 0;
2618
2619 if (GTK_WIDGET_CAN_DEFAULT(m_widget))
2620 {
2621 /* the default button has a border around it */
2622 border = 6;
2623 bottom_border = 5;
2624 }
2625
2626 DoMoveWindow( m_x-border,
2627 m_y-border,
2628 m_width+2*border,
2629 m_height+border+bottom_border );
2630 }
2631
2632 if (m_hasScrolling)
2633 {
2634 /* Sometimes the client area changes size without the
2635 whole windows's size changing, but if the whole
2636 windows's size doesn't change, no wxSizeEvent will
2637 normally be sent. Here we add an extra test if
2638 the client test has been changed and this will
2639 be used then. */
2640 GetClientSize( &m_oldClientWidth, &m_oldClientHeight );
2641 }
2642
2643 /*
2644 wxPrintf( "OnSize sent from " );
2645 if (GetClassInfo() && GetClassInfo()->GetClassName())
2646 wxPrintf( GetClassInfo()->GetClassName() );
2647 wxPrintf( " %d %d %d %d\n", (int)m_x, (int)m_y, (int)m_width, (int)m_height );
2648 */
2649
2650 if (!m_nativeSizeEvent)
2651 {
2652 wxSizeEvent event( wxSize(m_width,m_height), GetId() );
2653 event.SetEventObject( this );
2654 GetEventHandler()->ProcessEvent( event );
2655 }
2656
2657 m_resizing = FALSE;
2658 }
2659
2660 void wxWindow::OnInternalIdle()
2661 {
2662 if ( g_sendActivateEvent != -1 )
2663 {
2664 bool activate = g_sendActivateEvent != 0;
2665
2666 // do it only once
2667 g_sendActivateEvent = -1;
2668
2669 wxActivateEvent event(wxEVT_ACTIVATE_APP, activate, GetId());
2670 event.SetEventObject(this);
2671
2672 (void)GetEventHandler()->ProcessEvent(event);
2673 }
2674
2675 wxCursor cursor = m_cursor;
2676 if (g_globalCursor.Ok()) cursor = g_globalCursor;
2677
2678 if (cursor.Ok())
2679 {
2680 /* I now set the cursor anew in every OnInternalIdle call
2681 as setting the cursor in a parent window also effects the
2682 windows above so that checking for the current cursor is
2683 not possible. */
2684
2685 if (m_wxwindow)
2686 {
2687 GdkWindow *window = GTK_PIZZA(m_wxwindow)->bin_window;
2688 if (window)
2689 gdk_window_set_cursor( window, cursor.GetCursor() );
2690
2691 if (!g_globalCursor.Ok())
2692 cursor = *wxSTANDARD_CURSOR;
2693
2694 window = m_widget->window;
2695 if ((window) && !(GTK_WIDGET_NO_WINDOW(m_widget)))
2696 gdk_window_set_cursor( window, cursor.GetCursor() );
2697
2698 }
2699 else
2700 {
2701
2702 GdkWindow *window = m_widget->window;
2703 if ((window) && !(GTK_WIDGET_NO_WINDOW(m_widget)))
2704 gdk_window_set_cursor( window, cursor.GetCursor() );
2705
2706 }
2707 }
2708
2709 UpdateWindowUI();
2710 }
2711
2712 void wxWindow::DoGetSize( int *width, int *height ) const
2713 {
2714 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
2715
2716 if (width) (*width) = m_width;
2717 if (height) (*height) = m_height;
2718 }
2719
2720 void wxWindow::DoSetClientSize( int width, int height )
2721 {
2722 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
2723
2724 if (!m_wxwindow)
2725 {
2726 SetSize( width, height );
2727 }
2728 else
2729 {
2730 int dw = 0;
2731 int dh = 0;
2732
2733 if (HasFlag(wxRAISED_BORDER) || HasFlag(wxSUNKEN_BORDER))
2734 {
2735 /* when using GTK 1.2 we set the shadow border size to 2 */
2736 dw += 2 * 2;
2737 dh += 2 * 2;
2738 }
2739 if (HasFlag(wxSIMPLE_BORDER))
2740 {
2741 /* when using GTK 1.2 we set the simple border size to 1 */
2742 dw += 1 * 2;
2743 dh += 1 * 2;
2744 }
2745
2746 if (m_hasScrolling)
2747 {
2748 GtkScrolledWindow *scroll_window = GTK_SCROLLED_WINDOW(m_widget);
2749
2750 GtkRequisition vscroll_req;
2751 vscroll_req.width = 2;
2752 vscroll_req.height = 2;
2753 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->vscrollbar) )->size_request )
2754 (scroll_window->vscrollbar, &vscroll_req );
2755
2756 GtkRequisition hscroll_req;
2757 hscroll_req.width = 2;
2758 hscroll_req.height = 2;
2759 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->hscrollbar) )->size_request )
2760 (scroll_window->hscrollbar, &hscroll_req );
2761
2762 GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget) );
2763
2764 if (scroll_window->vscrollbar_visible)
2765 {
2766 dw += vscroll_req.width;
2767 dw += scroll_class->scrollbar_spacing;
2768 }
2769
2770 if (scroll_window->hscrollbar_visible)
2771 {
2772 dh += hscroll_req.height;
2773 dh += scroll_class->scrollbar_spacing;
2774 }
2775 }
2776
2777 SetSize( width+dw, height+dh );
2778 }
2779 }
2780
2781 void wxWindow::DoGetClientSize( int *width, int *height ) const
2782 {
2783 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
2784
2785 if (!m_wxwindow)
2786 {
2787 if (width) (*width) = m_width;
2788 if (height) (*height) = m_height;
2789 }
2790 else
2791 {
2792 int dw = 0;
2793 int dh = 0;
2794
2795 if (HasFlag(wxRAISED_BORDER) || HasFlag(wxSUNKEN_BORDER))
2796 {
2797 /* when using GTK 1.2 we set the shadow border size to 2 */
2798 dw += 2 * 2;
2799 dh += 2 * 2;
2800 }
2801 if (HasFlag(wxSIMPLE_BORDER))
2802 {
2803 /* when using GTK 1.2 we set the simple border size to 1 */
2804 dw += 1 * 2;
2805 dh += 1 * 2;
2806 }
2807
2808 if (m_hasScrolling)
2809 {
2810 GtkScrolledWindow *scroll_window = GTK_SCROLLED_WINDOW(m_widget);
2811
2812 GtkRequisition vscroll_req;
2813 vscroll_req.width = 2;
2814 vscroll_req.height = 2;
2815 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->vscrollbar) )->size_request )
2816 (scroll_window->vscrollbar, &vscroll_req );
2817
2818 GtkRequisition hscroll_req;
2819 hscroll_req.width = 2;
2820 hscroll_req.height = 2;
2821 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->hscrollbar) )->size_request )
2822 (scroll_window->hscrollbar, &hscroll_req );
2823
2824 GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget) );
2825
2826 if (scroll_window->vscrollbar_visible)
2827 {
2828 dw += vscroll_req.width;
2829 dw += scroll_class->scrollbar_spacing;
2830 }
2831
2832 if (scroll_window->hscrollbar_visible)
2833 {
2834 dh += hscroll_req.height;
2835 dh += scroll_class->scrollbar_spacing;
2836 }
2837 }
2838
2839 if (width) (*width) = m_width - dw;
2840 if (height) (*height) = m_height - dh;
2841 }
2842 }
2843
2844 void wxWindow::DoGetPosition( int *x, int *y ) const
2845 {
2846 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
2847
2848 int dx = 0;
2849 int dy = 0;
2850 if (m_parent && m_parent->m_wxwindow)
2851 {
2852 GtkPizza *pizza = GTK_PIZZA(m_parent->m_wxwindow);
2853 dx = pizza->xoffset;
2854 dy = pizza->yoffset;
2855 }
2856
2857 if (x) (*x) = m_x - dx;
2858 if (y) (*y) = m_y - dy;
2859 }
2860
2861 void wxWindow::DoClientToScreen( int *x, int *y ) const
2862 {
2863 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
2864
2865 if (!m_widget->window) return;
2866
2867 GdkWindow *source = (GdkWindow *) NULL;
2868 if (m_wxwindow)
2869 source = GTK_PIZZA(m_wxwindow)->bin_window;
2870 else
2871 source = m_widget->window;
2872
2873 int org_x = 0;
2874 int org_y = 0;
2875 gdk_window_get_origin( source, &org_x, &org_y );
2876
2877 if (!m_wxwindow)
2878 {
2879 if (GTK_WIDGET_NO_WINDOW (m_widget))
2880 {
2881 org_x += m_widget->allocation.x;
2882 org_y += m_widget->allocation.y;
2883 }
2884 }
2885
2886 if (x) *x += org_x;
2887 if (y) *y += org_y;
2888 }
2889
2890 void wxWindow::DoScreenToClient( int *x, int *y ) const
2891 {
2892 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
2893
2894 if (!m_widget->window) return;
2895
2896 GdkWindow *source = (GdkWindow *) NULL;
2897 if (m_wxwindow)
2898 source = GTK_PIZZA(m_wxwindow)->bin_window;
2899 else
2900 source = m_widget->window;
2901
2902 int org_x = 0;
2903 int org_y = 0;
2904 gdk_window_get_origin( source, &org_x, &org_y );
2905
2906 if (!m_wxwindow)
2907 {
2908 if (GTK_WIDGET_NO_WINDOW (m_widget))
2909 {
2910 org_x += m_widget->allocation.x;
2911 org_y += m_widget->allocation.y;
2912 }
2913 }
2914
2915 if (x) *x -= org_x;
2916 if (y) *y -= org_y;
2917 }
2918
2919 bool wxWindow::Show( bool show )
2920 {
2921 wxCHECK_MSG( (m_widget != NULL), FALSE, wxT("invalid window") );
2922
2923 if (!wxWindowBase::Show(show))
2924 {
2925 // nothing to do
2926 return FALSE;
2927 }
2928
2929 if (show)
2930 gtk_widget_show( m_widget );
2931 else
2932 gtk_widget_hide( m_widget );
2933
2934 return TRUE;
2935 }
2936
2937 static void wxWindowNotifyEnable(wxWindow* win, bool enable)
2938 {
2939 win->OnParentEnable(enable);
2940
2941 // Recurse, so that children have the opportunity to Do The Right Thing
2942 // and reset colours that have been messed up by a parent's (really ancestor's)
2943 // Enable call
2944 for ( wxWindowList::Node *node = win->GetChildren().GetFirst();
2945 node;
2946 node = node->GetNext() )
2947 {
2948 wxWindow *child = node->GetData();
2949 if (!child->IsKindOf(CLASSINFO(wxDialog)) && !child->IsKindOf(CLASSINFO(wxFrame)))
2950 wxWindowNotifyEnable(child, enable);
2951 }
2952 }
2953
2954 bool wxWindow::Enable( bool enable )
2955 {
2956 wxCHECK_MSG( (m_widget != NULL), FALSE, wxT("invalid window") );
2957
2958 if (!wxWindowBase::Enable(enable))
2959 {
2960 // nothing to do
2961 return FALSE;
2962 }
2963
2964 gtk_widget_set_sensitive( m_widget, enable );
2965 if ( m_wxwindow )
2966 gtk_widget_set_sensitive( m_wxwindow, enable );
2967
2968 wxWindowNotifyEnable(this, enable);
2969
2970 return TRUE;
2971 }
2972
2973 int wxWindow::GetCharHeight() const
2974 {
2975 wxCHECK_MSG( (m_widget != NULL), 12, wxT("invalid window") );
2976
2977 wxCHECK_MSG( m_font.Ok(), 12, wxT("invalid font") );
2978
2979 GdkFont *font = m_font.GetInternalFont( 1.0 );
2980
2981 return font->ascent + font->descent;
2982 }
2983
2984 int wxWindow::GetCharWidth() const
2985 {
2986 wxCHECK_MSG( (m_widget != NULL), 8, wxT("invalid window") );
2987
2988 wxCHECK_MSG( m_font.Ok(), 8, wxT("invalid font") );
2989
2990 GdkFont *font = m_font.GetInternalFont( 1.0 );
2991
2992 return gdk_string_width( font, "H" );
2993 }
2994
2995 void wxWindow::GetTextExtent( const wxString& string,
2996 int *x,
2997 int *y,
2998 int *descent,
2999 int *externalLeading,
3000 const wxFont *theFont ) const
3001 {
3002 wxFont fontToUse = m_font;
3003 if (theFont) fontToUse = *theFont;
3004
3005 wxCHECK_RET( fontToUse.Ok(), wxT("invalid font") );
3006
3007 GdkFont *font = fontToUse.GetInternalFont( 1.0 );
3008 if (x) (*x) = gdk_string_width( font, string.mbc_str() );
3009 if (y) (*y) = font->ascent + font->descent;
3010 if (descent) (*descent) = font->descent;
3011 if (externalLeading) (*externalLeading) = 0; // ??
3012 }
3013
3014 void wxWindow::SetFocus()
3015 {
3016 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3017
3018 if (m_wxwindow)
3019 {
3020 if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow))
3021 gtk_widget_grab_focus (m_wxwindow);
3022 return;
3023 }
3024
3025 if (m_widget)
3026 {
3027 if (GTK_WIDGET_CAN_FOCUS(m_widget) && !GTK_WIDGET_HAS_FOCUS (m_widget) )
3028 {
3029 gtk_widget_grab_focus (m_widget);
3030 }
3031 else if (GTK_IS_CONTAINER(m_widget))
3032 {
3033 gtk_container_focus( GTK_CONTAINER(m_widget), GTK_DIR_TAB_FORWARD );
3034 }
3035 else
3036 {
3037 // ?
3038 }
3039 }
3040 }
3041
3042 bool wxWindow::AcceptsFocus() const
3043 {
3044 return m_acceptsFocus && wxWindowBase::AcceptsFocus();
3045 }
3046
3047 bool wxWindow::Reparent( wxWindowBase *newParentBase )
3048 {
3049 wxCHECK_MSG( (m_widget != NULL), FALSE, wxT("invalid window") );
3050
3051 wxWindow *oldParent = m_parent,
3052 *newParent = (wxWindow *)newParentBase;
3053
3054 wxASSERT( GTK_IS_WIDGET(m_widget) );
3055
3056 if ( !wxWindowBase::Reparent(newParent) )
3057 return FALSE;
3058
3059 wxASSERT( GTK_IS_WIDGET(m_widget) );
3060
3061 /* prevent GTK from deleting the widget arbitrarily */
3062 gtk_widget_ref( m_widget );
3063
3064 if (oldParent)
3065 {
3066 gtk_container_remove( GTK_CONTAINER(m_widget->parent), m_widget );
3067 }
3068
3069 wxASSERT( GTK_IS_WIDGET(m_widget) );
3070
3071 if (newParent)
3072 {
3073 /* insert GTK representation */
3074 (*(newParent->m_insertCallback))(newParent, this);
3075 }
3076
3077 /* reverse: prevent GTK from deleting the widget arbitrarily */
3078 gtk_widget_unref( m_widget );
3079
3080 return TRUE;
3081 }
3082
3083 void wxWindow::DoAddChild(wxWindow *child)
3084 {
3085 wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
3086
3087 wxASSERT_MSG( (child != NULL), wxT("invalid child window") );
3088
3089 wxASSERT_MSG( (m_insertCallback != NULL), wxT("invalid child insertion function") );
3090
3091 /* add to list */
3092 AddChild( child );
3093
3094 /* insert GTK representation */
3095 (*m_insertCallback)(this, child);
3096 }
3097
3098 void wxWindow::Raise()
3099 {
3100 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3101
3102 if (!m_widget->window) return;
3103
3104 gdk_window_raise( m_widget->window );
3105 }
3106
3107 void wxWindow::Lower()
3108 {
3109 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3110
3111 if (!m_widget->window) return;
3112
3113 gdk_window_lower( m_widget->window );
3114 }
3115
3116 bool wxWindow::SetCursor( const wxCursor &cursor )
3117 {
3118 wxCHECK_MSG( (m_widget != NULL), FALSE, wxT("invalid window") );
3119
3120 if (cursor == m_cursor)
3121 return FALSE;
3122
3123 if (g_isIdle)
3124 wxapp_install_idle_handler();
3125
3126 if (cursor == wxNullCursor)
3127 return wxWindowBase::SetCursor( *wxSTANDARD_CURSOR );
3128 else
3129 return wxWindowBase::SetCursor( cursor );
3130 }
3131
3132 void wxWindow::WarpPointer( int x, int y )
3133 {
3134 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3135
3136 /* we provide this function ourselves as it is
3137 missing in GDK (top of this file) */
3138
3139 GdkWindow *window = (GdkWindow*) NULL;
3140 if (m_wxwindow)
3141 window = GTK_PIZZA(m_wxwindow)->bin_window;
3142 else
3143 window = GetConnectWidget()->window;
3144
3145 if (window)
3146 gdk_window_warp_pointer( window, x, y );
3147 }
3148
3149 void wxWindow::Refresh( bool eraseBackground, const wxRect *rect )
3150 {
3151 if (!m_widget) return;
3152 if (!m_widget->window) return;
3153
3154 if (eraseBackground && m_wxwindow && m_wxwindow->window)
3155 {
3156 if (rect)
3157 {
3158 gdk_window_clear_area( GTK_PIZZA(m_wxwindow)->bin_window,
3159 rect->x, rect->y,
3160 rect->width, rect->height );
3161 }
3162 else
3163 {
3164 gdk_window_clear( GTK_PIZZA(m_wxwindow)->bin_window );
3165 }
3166 }
3167
3168 /* there is no GTK equivalent of "draw only, don't clear" so we
3169 invent our own in the GtkPizza widget */
3170
3171 if (!rect)
3172 {
3173 if (m_wxwindow)
3174 {
3175
3176 /*
3177 GtkPizza *pizza = GTK_PIZZA(m_wxwindow);
3178 gboolean old_clear = pizza->clear_on_draw;
3179 gtk_pizza_set_clear( pizza, FALSE );
3180 gtk_widget_draw( m_wxwindow, (GdkRectangle*) NULL );
3181 gtk_pizza_set_clear( pizza, old_clear );
3182 */
3183 GdkEventExpose gdk_event;
3184 gdk_event.type = GDK_EXPOSE;
3185 gdk_event.window = GTK_PIZZA(m_wxwindow)->bin_window;
3186 gdk_event.count = 0;
3187 gdk_event.area.x = 0;
3188 gdk_event.area.y = 0;
3189 gdk_event.area.width = m_wxwindow->allocation.width;
3190 gdk_event.area.height = m_wxwindow->allocation.height;
3191 gtk_window_expose_callback( m_wxwindow, &gdk_event, this );
3192
3193 }
3194 else
3195 {
3196 gtk_widget_draw( m_widget, (GdkRectangle*) NULL );
3197 }
3198 }
3199 else
3200 {
3201
3202 if (m_wxwindow)
3203 {
3204 /*
3205 GtkPizza *pizza = GTK_PIZZA(m_wxwindow);
3206 gboolean old_clear = pizza->clear_on_draw;
3207 gtk_pizza_set_clear( pizza, FALSE );
3208
3209 GdkRectangle gdk_rect;
3210 gdk_rect.x = rect->x;
3211 gdk_rect.y = rect->y;
3212 gdk_rect.width = rect->width;
3213 gdk_rect.height = rect->height;
3214 gtk_widget_draw( m_wxwindow, &gdk_rect );
3215 gtk_window_draw_callback( m_wxwindow, &gdk_rect, this );
3216
3217 gtk_pizza_set_clear( pizza, old_clear );
3218 */
3219 GdkEventExpose gdk_event;
3220 gdk_event.type = GDK_EXPOSE;
3221 gdk_event.window = GTK_PIZZA(m_wxwindow)->bin_window;
3222 gdk_event.count = 0;
3223 gdk_event.area.x = rect->x;
3224 gdk_event.area.y = rect->y;
3225 gdk_event.area.width = rect->width;
3226 gdk_event.area.height = rect->height;
3227 gtk_window_expose_callback( m_wxwindow, &gdk_event, this );
3228 }
3229 else
3230 {
3231 GdkRectangle gdk_rect;
3232 gdk_rect.x = rect->x;
3233 gdk_rect.y = rect->y;
3234 gdk_rect.width = rect->width;
3235 gdk_rect.height = rect->height;
3236 gtk_widget_draw( m_widget, &gdk_rect );
3237 }
3238 }
3239 }
3240
3241 void wxWindow::Clear()
3242 {
3243 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
3244
3245 if (!m_widget->window) return;
3246
3247 if (m_wxwindow && m_wxwindow->window)
3248 {
3249 // gdk_window_clear( m_wxwindow->window );
3250 }
3251 }
3252
3253 #if wxUSE_TOOLTIPS
3254 void wxWindow::DoSetToolTip( wxToolTip *tip )
3255 {
3256 wxWindowBase::DoSetToolTip(tip);
3257
3258 if (m_tooltip)
3259 m_tooltip->Apply( this );
3260 }
3261
3262 void wxWindow::ApplyToolTip( GtkTooltips *tips, const wxChar *tip )
3263 {
3264 gtk_tooltips_set_tip( tips, GetConnectWidget(), wxConvCurrent->cWX2MB(tip), (gchar*) NULL );
3265 }
3266 #endif // wxUSE_TOOLTIPS
3267
3268 bool wxWindow::SetBackgroundColour( const wxColour &colour )
3269 {
3270 wxCHECK_MSG( m_widget != NULL, FALSE, wxT("invalid window") );
3271
3272 if (!wxWindowBase::SetBackgroundColour(colour))
3273 {
3274 // don't leave if the GTK widget has just
3275 // been realized
3276 if (!m_delayedBackgroundColour) return FALSE;
3277 }
3278
3279 GdkWindow *window = (GdkWindow*) NULL;
3280 if (m_wxwindow)
3281 window = GTK_PIZZA(m_wxwindow)->bin_window;
3282 else
3283 window = GetConnectWidget()->window;
3284
3285 if (!window)
3286 {
3287 // indicate that a new style has been set
3288 // but it couldn't get applied as the
3289 // widget hasn't been realized yet.
3290 m_delayedBackgroundColour = TRUE;
3291 }
3292
3293 if ((m_wxwindow) &&
3294 (m_wxwindow->window) &&
3295 (m_backgroundColour != wxSystemSettings::GetSystemColour(wxSYS_COLOUR_BTNFACE)))
3296 {
3297 /* wxMSW doesn't clear the window here. I don't do that either to
3298 provide compatibility. call Clear() to do the job. */
3299
3300 m_backgroundColour.CalcPixel( gdk_window_get_colormap( window ) );
3301 gdk_window_set_background( window, m_backgroundColour.GetColor() );
3302 }
3303
3304 ApplyWidgetStyle();
3305
3306 return TRUE;
3307 }
3308
3309 bool wxWindow::SetForegroundColour( const wxColour &colour )
3310 {
3311 wxCHECK_MSG( m_widget != NULL, FALSE, wxT("invalid window") );
3312
3313 if (!wxWindowBase::SetForegroundColour(colour))
3314 {
3315 // don't leave if the GTK widget has just
3316 // been realized
3317 if (!m_delayedForegroundColour) return FALSE;
3318 }
3319
3320 GdkWindow *window = (GdkWindow*) NULL;
3321 if (m_wxwindow)
3322 window = GTK_PIZZA(m_wxwindow)->bin_window;
3323 else
3324 window = GetConnectWidget()->window;
3325
3326 if (!window)
3327 {
3328 // indicate that a new style has been set
3329 // but it couldn't get applied as the
3330 // widget hasn't been realized yet.
3331 m_delayedForegroundColour = TRUE;
3332 }
3333
3334 ApplyWidgetStyle();
3335
3336 return TRUE;
3337 }
3338
3339 GtkStyle *wxWindow::GetWidgetStyle()
3340 {
3341 if (m_widgetStyle)
3342 {
3343 GtkStyle *remake = gtk_style_copy( m_widgetStyle );
3344 #ifdef __WXGTK20__
3345 /* FIXME: is this necessary? */
3346 _G_TYPE_IGC(remake, GtkObjectClass) = _G_TYPE_IGC(m_widgetStyle, GtkObjectClass);
3347 #else
3348 remake->klass = m_widgetStyle->klass;
3349 #endif
3350
3351 gtk_style_unref( m_widgetStyle );
3352 m_widgetStyle = remake;
3353 }
3354 else
3355 {
3356 GtkStyle *def = gtk_rc_get_style( m_widget );
3357
3358 if (!def)
3359 def = gtk_widget_get_default_style();
3360
3361 m_widgetStyle = gtk_style_copy( def );
3362 #ifdef __WXGTK20__
3363 /* FIXME: is this necessary? */
3364 _G_TYPE_IGC(m_widgetStyle, GtkObjectClass) = _G_TYPE_IGC(def, GtkObjectClass);
3365 #else
3366 m_widgetStyle->klass = def->klass;
3367 #endif
3368 }
3369
3370 return m_widgetStyle;
3371 }
3372
3373 void wxWindow::SetWidgetStyle()
3374 {
3375 #if DISABLE_STYLE_IF_BROKEN_THEM
3376 if (m_widget->style->engine_data)
3377 {
3378 static bool s_warningPrinted = FALSE;
3379 if (!s_warningPrinted)
3380 {
3381 printf( "wxWindows warning: Widget styles disabled due to buggy GTK theme.\n" );
3382 s_warningPrinted = TRUE;
3383 }
3384 m_widgetStyle = m_widget->style;
3385 return;
3386 }
3387 #endif
3388
3389 GtkStyle *style = GetWidgetStyle();
3390
3391 if (m_font != wxSystemSettings::GetSystemFont( wxSYS_DEFAULT_GUI_FONT ))
3392 {
3393 gdk_font_unref( style->font );
3394 style->font = gdk_font_ref( m_font.GetInternalFont( 1.0 ) );
3395 }
3396
3397 if (m_foregroundColour.Ok())
3398 {
3399 m_foregroundColour.CalcPixel( gtk_widget_get_colormap( m_widget ) );
3400 if (m_foregroundColour != wxSystemSettings::GetSystemColour(wxSYS_COLOUR_BTNTEXT))
3401 {
3402 style->fg[GTK_STATE_NORMAL] = *m_foregroundColour.GetColor();
3403 style->fg[GTK_STATE_PRELIGHT] = *m_foregroundColour.GetColor();
3404 style->fg[GTK_STATE_ACTIVE] = *m_foregroundColour.GetColor();
3405 }
3406 else
3407 {
3408 // Try to restore the gtk default style. This is still a little
3409 // oversimplified for what is probably really needed here for controls
3410 // other than buttons, but is better than not being able to (re)set a
3411 // control's foreground colour to *wxBLACK -- RL
3412 GtkStyle *def = gtk_rc_get_style( m_widget );
3413
3414 if (!def)
3415 def = gtk_widget_get_default_style();
3416
3417 style->fg[GTK_STATE_NORMAL] = def->fg[GTK_STATE_NORMAL];
3418 style->fg[GTK_STATE_PRELIGHT] = def->fg[GTK_STATE_PRELIGHT];
3419 style->fg[GTK_STATE_ACTIVE] = def->fg[GTK_STATE_ACTIVE];
3420 }
3421 }
3422
3423 if (m_backgroundColour.Ok())
3424 {
3425 m_backgroundColour.CalcPixel( gtk_widget_get_colormap( m_widget ) );
3426 if (m_backgroundColour != wxSystemSettings::GetSystemColour(wxSYS_COLOUR_BTNFACE))
3427 {
3428 style->bg[GTK_STATE_NORMAL] = *m_backgroundColour.GetColor();
3429 style->base[GTK_STATE_NORMAL] = *m_backgroundColour.GetColor();
3430 style->bg[GTK_STATE_PRELIGHT] = *m_backgroundColour.GetColor();
3431 style->base[GTK_STATE_PRELIGHT] = *m_backgroundColour.GetColor();
3432 style->bg[GTK_STATE_ACTIVE] = *m_backgroundColour.GetColor();
3433 style->base[GTK_STATE_ACTIVE] = *m_backgroundColour.GetColor();
3434 style->bg[GTK_STATE_INSENSITIVE] = *m_backgroundColour.GetColor();
3435 style->base[GTK_STATE_INSENSITIVE] = *m_backgroundColour.GetColor();
3436 }
3437 else
3438 {
3439 // Try to restore the gtk default style. This is still a little
3440 // oversimplified for what is probably really needed here for controls
3441 // other than buttons, but is better than not being able to (re)set a
3442 // control's background colour to default grey and means resetting a
3443 // button to wxSYS_COLOUR_BTNFACE will restore its usual highlighting
3444 // behavior -- RL
3445 GtkStyle *def = gtk_rc_get_style( m_widget );
3446
3447 if (!def)
3448 def = gtk_widget_get_default_style();
3449
3450 style->bg[GTK_STATE_NORMAL] = def->bg[GTK_STATE_NORMAL];
3451 style->base[GTK_STATE_NORMAL] = def->base[GTK_STATE_NORMAL];
3452 style->bg[GTK_STATE_PRELIGHT] = def->bg[GTK_STATE_PRELIGHT];
3453 style->base[GTK_STATE_PRELIGHT] = def->base[GTK_STATE_PRELIGHT];
3454 style->bg[GTK_STATE_ACTIVE] = def->bg[GTK_STATE_ACTIVE];
3455 style->base[GTK_STATE_ACTIVE] = def->base[GTK_STATE_ACTIVE];
3456 style->bg[GTK_STATE_INSENSITIVE] = def->bg[GTK_STATE_INSENSITIVE];
3457 style->base[GTK_STATE_INSENSITIVE] = def->base[GTK_STATE_INSENSITIVE];
3458 }
3459 }
3460 }
3461
3462 void wxWindow::ApplyWidgetStyle()
3463 {
3464 }
3465
3466 //-----------------------------------------------------------------------------
3467 // Pop-up menu stuff
3468 //-----------------------------------------------------------------------------
3469
3470 static void gtk_pop_hide_callback( GtkWidget *WXUNUSED(widget), bool* is_waiting )
3471 {
3472 *is_waiting = FALSE;
3473 }
3474
3475 static void SetInvokingWindow( wxMenu *menu, wxWindow *win )
3476 {
3477 menu->SetInvokingWindow( win );
3478 wxMenuItemList::Node *node = menu->GetMenuItems().GetFirst();
3479 while (node)
3480 {
3481 wxMenuItem *menuitem = node->GetData();
3482 if (menuitem->IsSubMenu())
3483 {
3484 SetInvokingWindow( menuitem->GetSubMenu(), win );
3485 }
3486
3487 node = node->GetNext();
3488 }
3489 }
3490
3491 static gint gs_pop_x = 0;
3492 static gint gs_pop_y = 0;
3493
3494 static void pop_pos_callback( GtkMenu * WXUNUSED(menu),
3495 gint *x, gint *y,
3496 wxWindow *win )
3497 {
3498 win->ClientToScreen( &gs_pop_x, &gs_pop_y );
3499 *x = gs_pop_x;
3500 *y = gs_pop_y;
3501 }
3502
3503 bool wxWindow::DoPopupMenu( wxMenu *menu, int x, int y )
3504 {
3505 wxCHECK_MSG( m_widget != NULL, FALSE, wxT("invalid window") );
3506
3507 wxCHECK_MSG( menu != NULL, FALSE, wxT("invalid popup-menu") );
3508
3509 SetInvokingWindow( menu, this );
3510
3511 menu->UpdateUI();
3512
3513 gs_pop_x = x;
3514 gs_pop_y = y;
3515
3516 bool is_waiting = TRUE;
3517
3518 gtk_signal_connect( GTK_OBJECT(menu->m_menu), "hide",
3519 GTK_SIGNAL_FUNC(gtk_pop_hide_callback), (gpointer)&is_waiting );
3520
3521 gtk_menu_popup(
3522 GTK_MENU(menu->m_menu),
3523 (GtkWidget *) NULL, // parent menu shell
3524 (GtkWidget *) NULL, // parent menu item
3525 (GtkMenuPositionFunc) pop_pos_callback,
3526 (gpointer) this, // client data
3527 0, // button used to activate it
3528 gs_timeLastClick // the time of activation
3529 );
3530
3531 while (is_waiting)
3532 {
3533 while (gtk_events_pending())
3534 gtk_main_iteration();
3535 }
3536
3537 return TRUE;
3538 }
3539
3540 #if wxUSE_DRAG_AND_DROP
3541
3542 void wxWindow::SetDropTarget( wxDropTarget *dropTarget )
3543 {
3544 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
3545
3546 GtkWidget *dnd_widget = GetConnectWidget();
3547
3548 if (m_dropTarget) m_dropTarget->UnregisterWidget( dnd_widget );
3549
3550 if (m_dropTarget) delete m_dropTarget;
3551 m_dropTarget = dropTarget;
3552
3553 if (m_dropTarget) m_dropTarget->RegisterWidget( dnd_widget );
3554 }
3555
3556 #endif // wxUSE_DRAG_AND_DROP
3557
3558 GtkWidget* wxWindow::GetConnectWidget()
3559 {
3560 GtkWidget *connect_widget = m_widget;
3561 if (m_wxwindow) connect_widget = m_wxwindow;
3562
3563 return connect_widget;
3564 }
3565
3566 bool wxWindow::IsOwnGtkWindow( GdkWindow *window )
3567 {
3568 if (m_wxwindow)
3569 return (window == GTK_PIZZA(m_wxwindow)->bin_window);
3570
3571 return (window == m_widget->window);
3572 }
3573
3574 bool wxWindow::SetFont( const wxFont &font )
3575 {
3576 wxCHECK_MSG( m_widget != NULL, FALSE, wxT("invalid window") );
3577
3578 if (!wxWindowBase::SetFont(font))
3579 {
3580 return FALSE;
3581 }
3582
3583 wxColour sysbg = wxSystemSettings::GetSystemColour( wxSYS_COLOUR_BTNFACE );
3584 if ( sysbg == m_backgroundColour )
3585 {
3586 m_backgroundColour = wxNullColour;
3587 ApplyWidgetStyle();
3588 m_backgroundColour = sysbg;
3589 }
3590 else
3591 {
3592 ApplyWidgetStyle();
3593 }
3594
3595 return TRUE;
3596 }
3597
3598 void wxWindow::CaptureMouse()
3599 {
3600 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
3601
3602 wxCHECK_RET( g_captureWindow == NULL, wxT("CaptureMouse called twice") );
3603
3604 GdkWindow *window = (GdkWindow*) NULL;
3605 if (m_wxwindow)
3606 window = GTK_PIZZA(m_wxwindow)->bin_window;
3607 else
3608 window = GetConnectWidget()->window;
3609
3610 if (!window) return;
3611
3612 wxCursor* cursor = & m_cursor;
3613 if (!cursor->Ok())
3614 cursor = wxSTANDARD_CURSOR;
3615
3616 gdk_pointer_grab( window, FALSE,
3617 (GdkEventMask)
3618 (GDK_BUTTON_PRESS_MASK |
3619 GDK_BUTTON_RELEASE_MASK |
3620 GDK_POINTER_MOTION_HINT_MASK |
3621 GDK_POINTER_MOTION_MASK),
3622 (GdkWindow *) NULL,
3623 cursor->GetCursor(),
3624 (guint32)GDK_CURRENT_TIME );
3625 g_captureWindow = this;
3626 }
3627
3628 void wxWindow::ReleaseMouse()
3629 {
3630 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
3631
3632 wxCHECK_RET( g_captureWindow, wxT("ReleaseMouse called twice") );
3633
3634 GdkWindow *window = (GdkWindow*) NULL;
3635 if (m_wxwindow)
3636 window = GTK_PIZZA(m_wxwindow)->bin_window;
3637 else
3638 window = GetConnectWidget()->window;
3639
3640 if (!window)
3641 return;
3642
3643 gdk_pointer_ungrab ( (guint32)GDK_CURRENT_TIME );
3644 g_captureWindow = (wxWindow*) NULL;
3645 }
3646
3647 bool wxWindow::IsRetained() const
3648 {
3649 return FALSE;
3650 }
3651
3652 void wxWindow::SetScrollbar( int orient, int pos, int thumbVisible,
3653 int range, bool refresh )
3654 {
3655 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
3656
3657 wxCHECK_RET( m_wxwindow != NULL, wxT("window needs client area for scrolling") );
3658
3659 m_hasScrolling = TRUE;
3660
3661 if (orient == wxHORIZONTAL)
3662 {
3663 float fpos = (float)pos;
3664 float frange = (float)range;
3665 float fthumb = (float)thumbVisible;
3666 if (fpos > frange-fthumb) fpos = frange-fthumb;
3667 if (fpos < 0.0) fpos = 0.0;
3668
3669 if ((fabs(frange-m_hAdjust->upper) < 0.2) &&
3670 (fabs(fthumb-m_hAdjust->page_size) < 0.2))
3671 {
3672 SetScrollPos( orient, pos, refresh );
3673 return;
3674 }
3675
3676 m_oldHorizontalPos = fpos;
3677
3678 m_hAdjust->lower = 0.0;
3679 m_hAdjust->upper = frange;
3680 m_hAdjust->value = fpos;
3681 m_hAdjust->step_increment = 1.0;
3682 m_hAdjust->page_increment = (float)(wxMax(fthumb,0));
3683 m_hAdjust->page_size = fthumb;
3684 }
3685 else
3686 {
3687 float fpos = (float)pos;
3688 float frange = (float)range;
3689 float fthumb = (float)thumbVisible;
3690 if (fpos > frange-fthumb) fpos = frange-fthumb;
3691 if (fpos < 0.0) fpos = 0.0;
3692
3693 if ((fabs(frange-m_vAdjust->upper) < 0.2) &&
3694 (fabs(fthumb-m_vAdjust->page_size) < 0.2))
3695 {
3696 SetScrollPos( orient, pos, refresh );
3697 return;
3698 }
3699
3700 m_oldVerticalPos = fpos;
3701
3702 m_vAdjust->lower = 0.0;
3703 m_vAdjust->upper = frange;
3704 m_vAdjust->value = fpos;
3705 m_vAdjust->step_increment = 1.0;
3706 m_vAdjust->page_increment = (float)(wxMax(fthumb,0));
3707 m_vAdjust->page_size = fthumb;
3708 }
3709
3710 if (orient == wxHORIZONTAL)
3711 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust), "changed" );
3712 else
3713 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust), "changed" );
3714 }
3715
3716 void wxWindow::SetScrollPos( int orient, int pos, bool WXUNUSED(refresh) )
3717 {
3718 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
3719
3720 wxCHECK_RET( m_wxwindow != NULL, wxT("window needs client area for scrolling") );
3721
3722 if (orient == wxHORIZONTAL)
3723 {
3724 float fpos = (float)pos;
3725 if (fpos > m_hAdjust->upper - m_hAdjust->page_size) fpos = m_hAdjust->upper - m_hAdjust->page_size;
3726 if (fpos < 0.0) fpos = 0.0;
3727 m_oldHorizontalPos = fpos;
3728
3729 if (fabs(fpos-m_hAdjust->value) < 0.2) return;
3730 m_hAdjust->value = fpos;
3731 }
3732 else
3733 {
3734 float fpos = (float)pos;
3735 if (fpos > m_vAdjust->upper - m_vAdjust->page_size) fpos = m_vAdjust->upper - m_vAdjust->page_size;
3736 if (fpos < 0.0) fpos = 0.0;
3737 m_oldVerticalPos = fpos;
3738
3739 if (fabs(fpos-m_vAdjust->value) < 0.2) return;
3740 m_vAdjust->value = fpos;
3741 }
3742
3743 if (m_wxwindow->window)
3744 {
3745 if (orient == wxHORIZONTAL)
3746 {
3747 gtk_signal_disconnect_by_func( GTK_OBJECT(m_hAdjust),
3748 (GtkSignalFunc) gtk_window_hscroll_callback, (gpointer) this );
3749
3750 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust), "value_changed" );
3751
3752 gtk_signal_connect( GTK_OBJECT(m_hAdjust), "value_changed",
3753 (GtkSignalFunc) gtk_window_hscroll_callback, (gpointer) this );
3754 }
3755 else
3756 {
3757 gtk_signal_disconnect_by_func( GTK_OBJECT(m_vAdjust),
3758 (GtkSignalFunc) gtk_window_vscroll_callback, (gpointer) this );
3759
3760 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust), "value_changed" );
3761
3762 gtk_signal_connect( GTK_OBJECT(m_vAdjust), "value_changed",
3763 (GtkSignalFunc) gtk_window_vscroll_callback, (gpointer) this );
3764 }
3765 }
3766 }
3767
3768 int wxWindow::GetScrollThumb( int orient ) const
3769 {
3770 wxCHECK_MSG( m_widget != NULL, 0, wxT("invalid window") );
3771
3772 wxCHECK_MSG( m_wxwindow != NULL, 0, wxT("window needs client area for scrolling") );
3773
3774 if (orient == wxHORIZONTAL)
3775 return (int)(m_hAdjust->page_size+0.5);
3776 else
3777 return (int)(m_vAdjust->page_size+0.5);
3778 }
3779
3780 int wxWindow::GetScrollPos( int orient ) const
3781 {
3782 wxCHECK_MSG( m_widget != NULL, 0, wxT("invalid window") );
3783
3784 wxCHECK_MSG( m_wxwindow != NULL, 0, wxT("window needs client area for scrolling") );
3785
3786 if (orient == wxHORIZONTAL)
3787 return (int)(m_hAdjust->value+0.5);
3788 else
3789 return (int)(m_vAdjust->value+0.5);
3790 }
3791
3792 int wxWindow::GetScrollRange( int orient ) const
3793 {
3794 wxCHECK_MSG( m_widget != NULL, 0, wxT("invalid window") );
3795
3796 wxCHECK_MSG( m_wxwindow != NULL, 0, wxT("window needs client area for scrolling") );
3797
3798 if (orient == wxHORIZONTAL)
3799 return (int)(m_hAdjust->upper+0.5);
3800 else
3801 return (int)(m_vAdjust->upper+0.5);
3802 }
3803
3804 void wxWindow::ScrollWindow( int dx, int dy, const wxRect* WXUNUSED(rect) )
3805 {
3806 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
3807
3808 wxCHECK_RET( m_wxwindow != NULL, wxT("window needs client area for scrolling") );
3809
3810 if ((dx == 0) && (dy == 0)) return;
3811
3812 m_clipPaintRegion = TRUE;
3813 gtk_pizza_scroll( GTK_PIZZA(m_wxwindow), -dx, -dy );
3814 m_clipPaintRegion = FALSE;
3815
3816 /*
3817 if (m_children.GetCount() > 0)
3818 {
3819 gtk_pizza_scroll( GTK_PIZZA(m_wxwindow), -dx, -dy );
3820 }
3821 else
3822 {
3823 GtkPizza *pizza = GTK_PIZZA(m_wxwindow);
3824
3825 pizza->xoffset -= dx;
3826 pizza->yoffset -= dy;
3827
3828 GdkGC *m_scrollGC = gdk_gc_new( pizza->bin_window );
3829 gdk_gc_set_exposures( m_scrollGC, TRUE );
3830
3831 int cw = 0;
3832 int ch = 0;
3833 GetClientSize( &cw, &ch );
3834 int w = cw - abs(dx);
3835 int h = ch - abs(dy);
3836
3837 if ((h < 0) || (w < 0))
3838 {
3839 Refresh();
3840 }
3841 else
3842 {
3843 int s_x = 0;
3844 int s_y = 0;
3845 if (dx < 0) s_x = -dx;
3846 if (dy < 0) s_y = -dy;
3847 int d_x = 0;
3848 int d_y = 0;
3849 if (dx > 0) d_x = dx;
3850 if (dy > 0) d_y = dy;
3851
3852 gdk_window_copy_area( pizza->bin_window, m_scrollGC, d_x, d_y,
3853 pizza->bin_window, s_x, s_y, w, h );
3854
3855 wxRect rect;
3856 if (dx < 0) rect.x = cw+dx; else rect.x = 0;
3857 if (dy < 0) rect.y = ch+dy; else rect.y = 0;
3858 if (dy != 0) rect.width = cw; else rect.width = abs(dx);
3859 if (dx != 0) rect.height = ch; else rect.height = abs(dy);
3860
3861 Refresh( TRUE, &rect );
3862 }
3863
3864 gdk_gc_unref( m_scrollGC );
3865 }
3866 */
3867 }
3868
3869 // Find the wxWindow at the current mouse position, also returning the mouse
3870 // position.
3871 wxWindow* wxFindWindowAtPointer(wxPoint& pt)
3872 {
3873 pt = wxGetMousePosition();
3874 wxWindow* found = wxFindWindowAtPoint(pt);
3875 return found;
3876 }
3877
3878 // Get the current mouse position.
3879 wxPoint wxGetMousePosition()
3880 {
3881 /* This crashes when used within wxHelpContext,
3882 so we have to use the X-specific implementation below.
3883 gint x, y;
3884 GdkModifierType *mask;
3885 (void) gdk_window_get_pointer(NULL, &x, &y, mask);
3886
3887 return wxPoint(x, y);
3888 */
3889
3890 int x, y;
3891 GdkWindow* windowAtPtr = gdk_window_at_pointer(& x, & y);
3892 if (!windowAtPtr)
3893 return wxPoint(-999, -999);
3894
3895 Display *display = GDK_WINDOW_XDISPLAY(windowAtPtr);
3896 Window rootWindow = RootWindowOfScreen (DefaultScreenOfDisplay(display));
3897 Window rootReturn, childReturn;
3898 int rootX, rootY, winX, winY;
3899 unsigned int maskReturn;
3900
3901 XQueryPointer (display,
3902 rootWindow,
3903 &rootReturn,
3904 &childReturn,
3905 &rootX, &rootY, &winX, &winY, &maskReturn);
3906 return wxPoint(rootX, rootY);
3907
3908 }
3909