Add opaque move support to wxGTK's wxMiniFrame.
[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/dcscreen.h"
19 #endif
20
21 #include "gtk/gtk.h"
22 #include "wx/gtk/win_gtk.h"
23 #include "wx/gtk/private.h"
24
25 #include <gdk/gdk.h>
26 #include <gdk/gdkprivate.h>
27 #include <gdk/gdkx.h>
28
29 //-----------------------------------------------------------------------------
30 // data
31 //-----------------------------------------------------------------------------
32
33 extern bool g_blockEventsOnDrag;
34 extern bool g_blockEventsOnScroll;
35 extern GtkWidget *wxGetRootWindow();
36
37 //-----------------------------------------------------------------------------
38 // "expose_event" of m_mainWidget
39 //-----------------------------------------------------------------------------
40
41 extern "C" {
42 static void gtk_window_own_expose_callback( GtkWidget *widget, GdkEventExpose *gdk_event, wxFrame *win )
43 {
44 if (g_isIdle) wxapp_install_idle_handler();
45
46 if (!win->m_hasVMT) return;
47 if (gdk_event->count > 0) return;
48
49 GtkPizza *pizza = GTK_PIZZA(widget);
50
51 gtk_paint_shadow (widget->style,
52 pizza->bin_window,
53 GTK_STATE_NORMAL,
54 GTK_SHADOW_OUT,
55 NULL, NULL, NULL, // FIXME: No clipping?
56 0, 0,
57 win->m_width, win->m_height);
58
59 if (!win->GetTitle().empty() &&
60 ((win->GetWindowStyle() & wxCAPTION) ||
61 (win->GetWindowStyle() & wxTINY_CAPTION_HORIZ) ||
62 (win->GetWindowStyle() & wxTINY_CAPTION_VERT)))
63 {
64 wxClientDC dc(win);
65 dc.SetFont( *wxSMALL_FONT );
66 int height = dc.GetCharHeight();
67
68 GdkGC *gc = gdk_gc_new( pizza->bin_window );
69 gdk_gc_set_foreground( gc, &widget->style->bg[GTK_STATE_SELECTED] );
70 gdk_draw_rectangle( pizza->bin_window, gc, TRUE,
71 3,
72 3,
73 win->m_width - 7,
74 height+1 );
75 g_object_unref (gc);
76
77 // Hack alert
78 dc.m_window = pizza->bin_window;
79 dc.SetTextForeground( *wxWHITE );
80 dc.DrawText( win->GetTitle(), 6, 3 );
81 }
82 }
83 }
84
85 //-----------------------------------------------------------------------------
86 // "button_press_event" of m_mainWidget
87 //-----------------------------------------------------------------------------
88
89 extern "C" {
90 static gint gtk_window_button_press_callback( GtkWidget *widget, GdkEventButton *gdk_event, wxMiniFrame *win )
91 {
92 if (g_isIdle) wxapp_install_idle_handler();
93
94 if (!win->m_hasVMT) return FALSE;
95 if (g_blockEventsOnDrag) return TRUE;
96 if (g_blockEventsOnScroll) return TRUE;
97
98 if (win->m_isDragging) return TRUE;
99
100 GtkPizza *pizza = GTK_PIZZA(widget);
101 if (gdk_event->window != pizza->bin_window) return TRUE;
102
103 wxClientDC dc(win);
104 dc.SetFont( *wxSMALL_FONT );
105 int height = dc.GetCharHeight() + 1;
106
107 if (gdk_event->y > height) return TRUE;
108
109 gdk_window_raise( win->m_widget->window );
110
111 gdk_pointer_grab( widget->window, FALSE,
112 (GdkEventMask)
113 (GDK_BUTTON_PRESS_MASK |
114 GDK_BUTTON_RELEASE_MASK |
115 GDK_POINTER_MOTION_MASK |
116 GDK_POINTER_MOTION_HINT_MASK |
117 GDK_BUTTON_MOTION_MASK |
118 GDK_BUTTON1_MOTION_MASK),
119 (GdkWindow *) NULL,
120 (GdkCursor *) NULL,
121 (unsigned int) GDK_CURRENT_TIME );
122
123 win->m_diffX = (int)gdk_event->x;
124 win->m_diffY = (int)gdk_event->y;
125 win->m_oldX = 0;
126 win->m_oldY = 0;
127
128 win->m_isDragging = true;
129
130 return TRUE;
131 }
132 }
133
134 //-----------------------------------------------------------------------------
135 // "button_release_event" of m_mainWidget
136 //-----------------------------------------------------------------------------
137
138 extern "C" {
139 static gint gtk_window_button_release_callback( GtkWidget *widget, GdkEventButton *gdk_event, wxMiniFrame *win )
140 {
141 if (g_isIdle) wxapp_install_idle_handler();
142
143 if (!win->m_hasVMT) return FALSE;
144 if (g_blockEventsOnDrag) return TRUE;
145 if (g_blockEventsOnScroll) return TRUE;
146
147 if (!win->m_isDragging) return TRUE;
148
149 win->m_isDragging = false;
150
151 int x = (int)gdk_event->x;
152 int y = (int)gdk_event->y;
153
154 gdk_pointer_ungrab ( (guint32)GDK_CURRENT_TIME );
155 int org_x = 0;
156 int org_y = 0;
157 gdk_window_get_origin( widget->window, &org_x, &org_y );
158 x += org_x - win->m_diffX;
159 y += org_y - win->m_diffY;
160 win->m_x = x;
161 win->m_y = y;
162 gtk_window_move( GTK_WINDOW(win->m_widget), x, y );
163
164 return TRUE;
165 }
166 }
167
168 //-----------------------------------------------------------------------------
169 // "motion_notify_event" of m_mainWidget
170 //-----------------------------------------------------------------------------
171
172 extern "C" {
173 static gint gtk_window_motion_notify_callback( GtkWidget *widget, GdkEventMotion *gdk_event, wxMiniFrame *win )
174 {
175 if (g_isIdle) wxapp_install_idle_handler();
176
177 if (!win->m_hasVMT) return FALSE;
178 if (g_blockEventsOnDrag) return TRUE;
179 if (g_blockEventsOnScroll) return TRUE;
180
181 if (!win->m_isDragging) return TRUE;
182
183 if (gdk_event->is_hint)
184 {
185 int x = 0;
186 int y = 0;
187 GdkModifierType state;
188 gdk_window_get_pointer(gdk_event->window, &x, &y, &state);
189 gdk_event->x = x;
190 gdk_event->y = y;
191 gdk_event->state = state;
192 }
193
194 win->m_oldX = (int)gdk_event->x - win->m_diffX;
195 win->m_oldY = (int)gdk_event->y - win->m_diffY;
196
197 int x = (int)gdk_event->x;
198 int y = (int)gdk_event->y;
199
200 int org_x = 0;
201 int org_y = 0;
202 gdk_window_get_origin( widget->window, &org_x, &org_y );
203 x += org_x - win->m_diffX;
204 y += org_y - win->m_diffY;
205 win->m_x = x;
206 win->m_y = y;
207 gtk_window_move( GTK_WINDOW(win->m_widget), x, y );
208
209
210 return TRUE;
211 }
212 }
213
214 //-----------------------------------------------------------------------------
215 // "clicked" of X system button
216 //-----------------------------------------------------------------------------
217
218 extern "C" {
219 static void gtk_button_clicked_callback( GtkWidget *WXUNUSED(widget), wxMiniFrame *mf )
220 {
221 if (g_isIdle) wxapp_install_idle_handler();
222
223 mf->Close();
224 }
225 }
226
227 //-----------------------------------------------------------------------------
228 // wxMiniFrame
229 //-----------------------------------------------------------------------------
230
231 static const char *cross_xpm[] = {
232 /* columns rows colors chars-per-pixel */
233 "5 5 2 1",
234 "# c Gray0",
235 " c None",
236 /* pixels */
237 "# #",
238 " # # ",
239 " # ",
240 " # # ",
241 "# #",
242 };
243
244 IMPLEMENT_DYNAMIC_CLASS(wxMiniFrame,wxFrame)
245
246 bool wxMiniFrame::Create( wxWindow *parent, wxWindowID id, const wxString &title,
247 const wxPoint &pos, const wxSize &size,
248 long style, const wxString &name )
249 {
250 style = style | wxCAPTION;
251
252 if ((style & wxCAPTION) || (style & wxTINY_CAPTION_HORIZ) || (style & wxTINY_CAPTION_VERT))
253 m_miniTitle = 13;
254
255 m_miniEdge = 3;
256 m_isDragging = false;
257 m_oldX = -1;
258 m_oldY = -1;
259 m_diffX = 0;
260 m_diffY = 0;
261
262 wxFrame::Create( parent, id, title, pos, size, style, name );
263
264 if (m_parent && (GTK_IS_WINDOW(m_parent->m_widget)))
265 {
266 gtk_window_set_transient_for( GTK_WINDOW(m_widget), GTK_WINDOW(m_parent->m_widget) );
267 }
268
269 if ((style & wxSYSTEM_MENU) &&
270 ((style & wxCAPTION) || (style & wxTINY_CAPTION_HORIZ) || (style & wxTINY_CAPTION_VERT)))
271 {
272 GdkBitmap *mask = (GdkBitmap*) NULL;
273 GdkPixmap *pixmap = gdk_pixmap_create_from_xpm_d
274 (
275 wxGetRootWindow()->window,
276 &mask,
277 NULL,
278 (char **)cross_xpm
279 );
280
281 GtkWidget *pw = gtk_pixmap_new( pixmap, mask );
282 g_object_unref (mask);
283 g_object_unref (pixmap);
284 gtk_widget_show( pw );
285
286 GtkWidget *close_button = gtk_button_new();
287 #ifdef __WXGTK24__
288 if (!gtk_check_version(2,4,0))
289 gtk_button_set_focus_on_click( GTK_BUTTON(close_button), FALSE );
290 #endif
291 gtk_container_add( GTK_CONTAINER(close_button), pw );
292
293 gtk_pizza_put( GTK_PIZZA(m_mainWidget),
294 close_button,
295 size.x-16, 4, 11, 11 );
296
297 gtk_widget_show( close_button );
298
299 g_signal_connect (close_button, "clicked",
300 G_CALLBACK (gtk_button_clicked_callback),
301 this);
302 }
303
304 /* these are called when the borders are drawn */
305 g_signal_connect (m_mainWidget, "expose_event",
306 G_CALLBACK (gtk_window_own_expose_callback), this );
307
308 /* these are required for dragging the mini frame around */
309 g_signal_connect (m_mainWidget, "button_press_event",
310 G_CALLBACK (gtk_window_button_press_callback), this);
311 g_signal_connect (m_mainWidget, "button_release_event",
312 G_CALLBACK (gtk_window_button_release_callback), this);
313 g_signal_connect (m_mainWidget, "motion_notify_event",
314 G_CALLBACK (gtk_window_motion_notify_callback), this);
315
316 return true;
317 }
318
319 void wxMiniFrame::SetTitle( const wxString &title )
320 {
321 wxFrame::SetTitle( title );
322
323 gdk_window_invalidate_rect( GTK_PIZZA(m_mainWidget)->bin_window, NULL, true );
324 }
325
326 #endif // wxUSE_MINIFRAME