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