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