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