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