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