]> git.saurik.com Git - wxWidgets.git/blob - src/gtk/minifram.cpp
Fix scrolling bug where client size was reported wrong
[wxWidgets.git] / src / gtk / minifram.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/gtk/minifram.cpp
3 // Purpose:
4 // Author: Robert Roebling
5 // Id: $Id$
6 // Copyright: (c) 1998 Robert Roebling
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
9
10 // For compilers that support precompilation, includes "wx.h".
11 #include "wx/wxprec.h"
12
13 #if wxUSE_MINIFRAME
14
15 #include "wx/minifram.h"
16
17 #ifndef WX_PRECOMP
18 #include "wx/settings.h"
19 #include "wx/dcclient.h"
20 #include "wx/image.h"
21 #endif
22
23 #include "wx/gtk/win_gtk.h"
24 #include "wx/gtk/private.h"
25
26 //-----------------------------------------------------------------------------
27 // data
28 //-----------------------------------------------------------------------------
29
30 extern bool g_blockEventsOnDrag;
31 extern bool g_blockEventsOnScroll;
32 extern GtkWidget *wxGetRootWindow();
33
34 //-----------------------------------------------------------------------------
35 // "expose_event" of m_mainWidget
36 //-----------------------------------------------------------------------------
37
38 // StepColour() it a utility function that simply darkens
39 // or lightens a color, based on the specified percentage
40 static wxColor StepColour(const wxColor& c, int percent)
41 {
42 int r = c.Red(), g = c.Green(), b = c.Blue();
43 return wxColour((unsigned char)wxMin((r*percent)/100,255),
44 (unsigned char)wxMin((g*percent)/100,255),
45 (unsigned char)wxMin((b*percent)/100,255));
46 }
47
48 static wxColor LightContrastColour(const wxColour& c)
49 {
50 int amount = 120;
51
52 // if the color is especially dark, then
53 // make the contrast even lighter
54 if (c.Red() < 128 && c.Green() < 128 && c.Blue() < 128)
55 amount = 160;
56
57 return StepColour(c, amount);
58 }
59
60 extern "C" {
61 static void gtk_window_own_expose_callback( GtkWidget *widget, GdkEventExpose *gdk_event, wxMiniFrame *win )
62 {
63 // don't need to install idle handler, its done from "event" signal
64
65 if (!win->m_hasVMT) return;
66 if (gdk_event->count > 0) return;
67
68 GtkPizza *pizza = GTK_PIZZA(widget);
69
70 gtk_paint_shadow (widget->style,
71 pizza->bin_window,
72 GTK_STATE_NORMAL,
73 GTK_SHADOW_OUT,
74 NULL, NULL, NULL, // FIXME: No clipping?
75 0, 0,
76 win->m_width, win->m_height);
77
78 int style = win->GetWindowStyle();
79
80 wxClientDC dc(win);
81 // Hack alert
82 dc.m_window = pizza->bin_window;
83
84 if (style & wxRESIZE_BORDER)
85 {
86 dc.SetBrush( *wxGREY_BRUSH );
87 dc.SetPen( *wxTRANSPARENT_PEN );
88 dc.DrawRectangle( win->m_width - 14, win->m_height-14, 14, 14 );
89 }
90
91 if (!win->GetTitle().empty() &&
92 ((style & wxCAPTION) ||
93 (style & wxTINY_CAPTION_HORIZ) ||
94 (style & wxTINY_CAPTION_VERT)))
95 {
96 dc.SetFont( *wxSMALL_FONT );
97 int height = dc.GetCharHeight();
98
99 wxBrush brush( LightContrastColour( wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT) ) );
100 dc.SetBrush( brush );
101 dc.SetPen( *wxTRANSPARENT_PEN );
102 dc.DrawRectangle( 3, 3, win->m_width - 7, height-2 );
103
104 dc.SetTextForeground( *wxWHITE );
105 dc.DrawText( win->GetTitle(), 6, 3 );
106
107 if (style & wxCLOSE_BOX)
108 dc.DrawBitmap( win->m_closeButton, win->m_width-19, 3, true );
109 }
110 }
111 }
112
113 //-----------------------------------------------------------------------------
114 // "button_press_event" of m_mainWidget
115 //-----------------------------------------------------------------------------
116
117 extern "C" {
118 static gint gtk_window_button_press_callback( GtkWidget *widget, GdkEventButton *gdk_event, wxMiniFrame *win )
119 {
120 // don't need to install idle handler, its done from "event" signal
121
122 if (!win->m_hasVMT) return FALSE;
123 if (g_blockEventsOnDrag) return TRUE;
124 if (g_blockEventsOnScroll) return TRUE;
125
126 if (win->m_isDragging) return TRUE;
127
128 GtkPizza *pizza = GTK_PIZZA(widget);
129 if (gdk_event->window != pizza->bin_window) return TRUE;
130
131 int style = win->GetWindowStyle();
132
133 int y = (int)gdk_event->y;
134 int x = (int)gdk_event->x;
135
136 if ((style & wxRESIZE_BORDER) &&
137 (x > win->m_width-14) && (y > win->m_height-14))
138 {
139 GtkWidget *ancestor = gtk_widget_get_toplevel( widget );
140
141 GdkWindow *source = GTK_PIZZA(widget)->bin_window;
142
143 int org_x = 0;
144 int org_y = 0;
145 gdk_window_get_origin( source, &org_x, &org_y );
146
147 gtk_window_begin_resize_drag (GTK_WINDOW (ancestor),
148 GDK_WINDOW_EDGE_SOUTH_EAST,
149 1,
150 org_x + x,
151 org_y + y,
152 0);
153
154 return TRUE;
155 }
156
157 if ((style & wxCLOSE_BOX) &&
158 ((style & wxCAPTION) || (style & wxTINY_CAPTION_HORIZ) || (style & wxTINY_CAPTION_VERT)))
159 {
160 if ((y > 3) && (y < 19) && (x > win->m_width-19) && (x < win->m_width-3))
161 {
162 win->Close();
163 return TRUE;
164 }
165 }
166
167 wxClientDC dc(win);
168 dc.SetFont( *wxSMALL_FONT );
169 int height = dc.GetCharHeight() + 1;
170
171
172 if (y > height) return TRUE;
173
174 gdk_window_raise( win->m_widget->window );
175
176 gdk_pointer_grab( widget->window, FALSE,
177 (GdkEventMask)
178 (GDK_BUTTON_PRESS_MASK |
179 GDK_BUTTON_RELEASE_MASK |
180 GDK_POINTER_MOTION_MASK |
181 GDK_POINTER_MOTION_HINT_MASK |
182 GDK_BUTTON_MOTION_MASK |
183 GDK_BUTTON1_MOTION_MASK),
184 (GdkWindow *) NULL,
185 (GdkCursor *) NULL,
186 (unsigned int) GDK_CURRENT_TIME );
187
188 win->m_diffX = x;
189 win->m_diffY = y;
190 win->m_oldX = 0;
191 win->m_oldY = 0;
192
193 win->m_isDragging = true;
194
195 return TRUE;
196 }
197 }
198
199 //-----------------------------------------------------------------------------
200 // "button_release_event" of m_mainWidget
201 //-----------------------------------------------------------------------------
202
203 extern "C" {
204 static gint gtk_window_button_release_callback( GtkWidget *widget, GdkEventButton *gdk_event, wxMiniFrame *win )
205 {
206 // don't need to install idle handler, its done from "event" signal
207
208 if (!win->m_hasVMT) return FALSE;
209 if (g_blockEventsOnDrag) return TRUE;
210 if (g_blockEventsOnScroll) return TRUE;
211
212 if (!win->m_isDragging) return TRUE;
213
214 win->m_isDragging = false;
215
216 int x = (int)gdk_event->x;
217 int y = (int)gdk_event->y;
218
219 gdk_pointer_ungrab ( (guint32)GDK_CURRENT_TIME );
220 int org_x = 0;
221 int org_y = 0;
222 gdk_window_get_origin( widget->window, &org_x, &org_y );
223 x += org_x - win->m_diffX;
224 y += org_y - win->m_diffY;
225 win->m_x = x;
226 win->m_y = y;
227 gtk_window_move( GTK_WINDOW(win->m_widget), x, y );
228
229 return TRUE;
230 }
231 }
232
233 //-----------------------------------------------------------------------------
234 // "leave_notify_event" of m_mainWidget
235 //-----------------------------------------------------------------------------
236
237 extern "C" {
238 static gboolean
239 gtk_window_leave_callback( GtkWidget *widget, GdkEventCrossing *gdk_event, wxMiniFrame *win )
240 {
241 // don't need to install idle handler, its done from "event" signal
242
243 if (!win->m_hasVMT) return FALSE;
244 if (g_blockEventsOnDrag) return FALSE;
245
246 gdk_window_set_cursor( widget->window, NULL );
247
248 return FALSE;
249 }
250 }
251
252 //-----------------------------------------------------------------------------
253 // "motion_notify_event" of m_mainWidget
254 //-----------------------------------------------------------------------------
255
256 extern "C" {
257 static gint
258 gtk_window_motion_notify_callback( GtkWidget *widget, GdkEventMotion *gdk_event, wxMiniFrame *win )
259 {
260 // don't need to install idle handler, its done from "event" signal
261
262 if (!win->m_hasVMT) return FALSE;
263 if (g_blockEventsOnDrag) return TRUE;
264 if (g_blockEventsOnScroll) return TRUE;
265
266 if (gdk_event->is_hint)
267 {
268 int x = 0;
269 int y = 0;
270 GdkModifierType state;
271 gdk_window_get_pointer(gdk_event->window, &x, &y, &state);
272 gdk_event->x = x;
273 gdk_event->y = y;
274 gdk_event->state = state;
275 }
276
277 int style = win->GetWindowStyle();
278
279 int x = (int)gdk_event->x;
280 int y = (int)gdk_event->y;
281
282 if (!win->m_isDragging)
283 {
284 if (style & wxRESIZE_BORDER)
285 {
286 if ((x > win->m_width-14) && (y > win->m_height-14))
287 gdk_window_set_cursor( widget->window, gdk_cursor_new( GDK_BOTTOM_RIGHT_CORNER ) );
288 else
289 gdk_window_set_cursor( widget->window, NULL );
290 }
291 return TRUE;
292 }
293
294 win->m_oldX = x - win->m_diffX;
295 win->m_oldY = y - win->m_diffY;
296
297 int org_x = 0;
298 int org_y = 0;
299 gdk_window_get_origin( widget->window, &org_x, &org_y );
300 x += org_x - win->m_diffX;
301 y += org_y - win->m_diffY;
302 win->m_x = x;
303 win->m_y = y;
304 gtk_window_move( GTK_WINDOW(win->m_widget), x, y );
305
306
307 return TRUE;
308 }
309 }
310
311 //-----------------------------------------------------------------------------
312 // wxMiniFrame
313 //-----------------------------------------------------------------------------
314
315 static unsigned char close_bits[]={
316 0xff, 0xff, 0xff, 0xff, 0x07, 0xf0, 0xfb, 0xef, 0xdb, 0xed, 0x8b, 0xe8,
317 0x1b, 0xec, 0x3b, 0xee, 0x1b, 0xec, 0x8b, 0xe8, 0xdb, 0xed, 0xfb, 0xef,
318 0x07, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
319
320
321 IMPLEMENT_DYNAMIC_CLASS(wxMiniFrame,wxFrame)
322
323 bool wxMiniFrame::Create( wxWindow *parent, wxWindowID id, const wxString &title,
324 const wxPoint &pos, const wxSize &size,
325 long style, const wxString &name )
326 {
327 style = style | wxCAPTION;
328
329 if ((style & wxCAPTION) || (style & wxTINY_CAPTION_HORIZ) || (style & wxTINY_CAPTION_VERT))
330 m_miniTitle = 16;
331
332 if (style & wxRESIZE_BORDER)
333 m_miniEdge = 4;
334 else
335 m_miniEdge = 3;
336 m_isDragging = false;
337 m_oldX = -1;
338 m_oldY = -1;
339 m_diffX = 0;
340 m_diffY = 0;
341
342 wxFrame::Create( parent, id, title, pos, size, style, name );
343
344 if (m_parent && (GTK_IS_WINDOW(m_parent->m_widget)))
345 {
346 gtk_window_set_transient_for( GTK_WINDOW(m_widget), GTK_WINDOW(m_parent->m_widget) );
347 }
348
349 if ((style & wxCLOSE_BOX) &&
350 ((style & wxCAPTION) || (style & wxTINY_CAPTION_HORIZ) || (style & wxTINY_CAPTION_VERT)))
351 {
352 wxImage img = wxBitmap((const char*)close_bits, 16, 16).ConvertToImage();
353 img.Replace(0,0,0,123,123,123);
354 img.SetMaskColour(123,123,123);
355 m_closeButton = wxBitmap( img );
356 }
357
358 /* these are called when the borders are drawn */
359 g_signal_connect (m_mainWidget, "expose_event",
360 G_CALLBACK (gtk_window_own_expose_callback), this );
361
362 /* these are required for dragging the mini frame around */
363 g_signal_connect (m_mainWidget, "button_press_event",
364 G_CALLBACK (gtk_window_button_press_callback), this);
365 g_signal_connect (m_mainWidget, "button_release_event",
366 G_CALLBACK (gtk_window_button_release_callback), this);
367 g_signal_connect (m_mainWidget, "motion_notify_event",
368 G_CALLBACK (gtk_window_motion_notify_callback), this);
369 g_signal_connect (m_mainWidget, "leave_notify_event",
370 G_CALLBACK (gtk_window_leave_callback), this);
371 return true;
372 }
373
374 void wxMiniFrame::SetTitle( const wxString &title )
375 {
376 wxFrame::SetTitle( title );
377
378 if (GTK_PIZZA(m_mainWidget)->bin_window)
379 gdk_window_invalidate_rect( GTK_PIZZA(m_mainWidget)->bin_window, NULL, true );
380 }
381
382 #endif // wxUSE_MINIFRAME