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