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