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