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