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