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