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