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