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