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