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