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