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