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