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