1 /*
2
3 toolbar-standalone-gtk.c: toolbar implementation with GTK+
4
5 Copyright (c) 2003-2013 uim Project https://github.com/uim/uim
6
7 All rights reserved.
8
9 Redistribution and use in source and binary forms, with or without
10 modification, are permitted provided that the following conditions
11 are met:
12
13 1. Redistributions of source code must retain the above copyright
14 notice, this list of conditions and the following disclaimer.
15 2. Redistributions in binary form must reproduce the above copyright
16 notice, this list of conditions and the following disclaimer in the
17 documentation and/or other materials provided with the distribution.
18 3. Neither the name of authors nor the names of its contributors
19 may be used to endorse or promote products derived from this software
20 without specific prior written permission.
21
22 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND
23 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE
26 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 SUCH DAMAGE.
33
34 */
35
36 #ifdef HAVE_CONFIG_H
37 # include <config.h>
38 #endif
39
40 #include <locale.h>
41 #include <uim/gettext.h>
42 #include <gtk/gtk.h>
43 #include "uim/uim.h"
44
45 extern GtkWidget *uim_toolbar_standalone_new(void);
46
47 static gboolean toolbar_dragging = FALSE;
48 static gint window_drag_start_x = -1, window_drag_start_y = -1;
49 static gint pointer_drag_start_x = -1, pointer_drag_start_y = -1;
50 static void size_request_cb(GtkWidget *widget, GtkRequisition *req,
51 gpointer data);
52
53 #if GLIB_CHECK_VERSION(2, 6, 0)
54
55 static void
parse_options(gint argc,gchar ** argv)56 parse_options(gint argc, gchar **argv)
57 {
58
59 }
60
61 #endif
62
63 static void
delete_event(GtkWidget * widget,gpointer data)64 delete_event(GtkWidget *widget, gpointer data)
65 {
66 gtk_main_quit();
67 }
68
69 static gboolean
button_press_event_cb(GtkWidget * widget,GdkEventButton * event,gpointer data)70 button_press_event_cb(GtkWidget *widget, GdkEventButton *event, gpointer data)
71 {
72 GdkCursor *cursor;
73 GtkWidget *toolbar;
74 gint height, width;
75 #if GTK_CHECK_VERSION(3, 0, 0)
76 GdkDevice *device = gtk_get_current_event_device();
77 #endif
78
79 /* do nothing unless left mouse button is pressed */
80 if (event->button != 1)
81 return FALSE;
82
83 switch (event->type) {
84 case GDK_BUTTON_PRESS:
85 cursor = gdk_cursor_new(GDK_FLEUR);
86 #if GTK_CHECK_VERSION(3, 0, 0)
87 gdk_device_grab(device, gtk_widget_get_window(widget),
88 GDK_OWNERSHIP_NONE, FALSE,
89 #else
90 gdk_pointer_grab(gtk_widget_get_window(widget), FALSE,
91 #endif
92 GDK_BUTTON_RELEASE_MASK |
93 GDK_POINTER_MOTION_MASK,
94 #if !GTK_CHECK_VERSION(3, 0, 0)
95 NULL,
96 #endif
97 cursor, event->time);
98 #if GTK_CHECK_VERSION(3, 0, 0)
99 g_object_unref(cursor);
100 #else
101 gdk_cursor_unref(cursor);
102 #endif
103
104 gtk_window_get_position(GTK_WINDOW(widget),
105 &window_drag_start_x,
106 &window_drag_start_y);
107 pointer_drag_start_x = (gint)event->x_root;
108 pointer_drag_start_y = (gint)event->y_root;
109 toolbar_dragging = TRUE;
110 break;
111 case GDK_2BUTTON_PRESS:
112 toolbar = GTK_WIDGET(data);
113 #if GTK_CHECK_VERSION(2, 18, 0)
114 if (gtk_widget_get_visible(toolbar)) {
115 #else
116 if (GTK_WIDGET_VISIBLE(toolbar)) {
117 #endif
118 gtk_window_get_size(GTK_WINDOW(widget), &width, &height);
119 gtk_widget_hide(toolbar);
120 } else {
121 height = -1;
122 gtk_widget_show(toolbar);
123 }
124 #if GTK_CHECK_VERSION(2, 90, 0)
125 {
126 GtkRequisition minimum_size, natural_size;
127 gtk_widget_get_preferred_size(widget, &minimum_size, &natural_size);
128 if (height > 0)
129 natural_size.height = height;
130 else if (height == 0)
131 natural_size.height = minimum_size.height;
132 size_request_cb(widget, &natural_size, NULL);
133 }
134 #else
135 gtk_widget_set_size_request(widget, -1, height);
136 #endif
137 break;
138 default:
139 break;
140 }
141
142 return FALSE;
143 }
144
145 static void
146 helper_win_set_position(GtkWidget *window, gint x, gint y)
147 {
148 gint wx = x, wy = y;
149 gint w, h, sc_w, sc_h;
150
151 sc_w = gdk_screen_width();
152 sc_h = gdk_screen_height();
153
154 #if GTK_CHECK_VERSION(2, 90, 0)
155 w = gdk_window_get_width(gtk_widget_get_window(window));
156 h = gdk_window_get_height(gtk_widget_get_window(window));
157 #else
158 gdk_drawable_get_size(gtk_widget_get_window(window), &w, &h);
159 #endif
160
161 if (wx < 0)
162 wx = 0;
163 else if (wx > sc_w - w)
164 wx = sc_w - w;
165 if (wy < 0)
166 wy = 0;
167 else if (wy > sc_h - h)
168 wy = sc_h -h;
169
170 g_object_set_data(G_OBJECT(window), "position_x", GINT_TO_POINTER(wx));
171 g_object_set_data(G_OBJECT(window), "position_y", GINT_TO_POINTER(wy));
172 gtk_window_move(GTK_WINDOW(window), wx, wy);
173 }
174
175 static gboolean
176 motion_notify_event_cb(GtkWidget *widget, GdkEventMotion *event, gpointer data)
177 {
178 if (toolbar_dragging) {
179 gint wx, wy;
180
181 wx = window_drag_start_x + ((gint)event->x_root - pointer_drag_start_x);
182 wy = window_drag_start_y + ((gint)event->y_root - pointer_drag_start_y);
183
184 helper_win_set_position(widget, wx, wy);
185
186 return TRUE;
187 }
188
189 return FALSE;
190 }
191
192 static gboolean
193 button_release_event_cb(GtkWidget *widget, GdkEventButton *event, gpointer data)
194 {
195 if (!toolbar_dragging)
196 return FALSE;
197
198 #if GTK_CHECK_VERSION(3, 0, 0)
199 gdk_device_ungrab(gtk_get_current_event_device(), event->time);
200 #else
201 gdk_pointer_ungrab(event->time);
202 #endif
203
204 pointer_drag_start_x = -1;
205 pointer_drag_start_y = -1;
206 toolbar_dragging = FALSE;
207
208 return FALSE;
209 }
210
211 #if GTK_CHECK_VERSION(2, 90, 0)
212 static gboolean
213 handle_draw_cb(GtkWidget *widget, cairo_t *cr)
214 {
215 gtk_render_handle(gtk_widget_get_style_context(widget), cr,
216 0, 0,
217 gtk_widget_get_allocated_width(widget),
218 gtk_widget_get_allocated_height(widget));
219 return FALSE;
220 }
221
222 #else
223 static gboolean
224 handle_expose_event_cb(GtkWidget *widget, GdkEventExpose *event)
225 {
226 GdkRectangle *rect = &event->area;
227
228 #if GTK_CHECK_VERSION(2, 18, 0)
229 GtkAllocation allocation;
230 gtk_widget_get_allocation(widget, &allocation);
231 gtk_paint_handle(gtk_widget_get_style(widget), gtk_widget_get_window(widget),
232 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
233 rect, widget, "handlebox",
234 allocation.x, allocation.y,
235 allocation.width, allocation.height,
236 GTK_ORIENTATION_VERTICAL);
237 #else
238 gtk_paint_handle(widget->style, widget->window,
239 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
240 rect, widget, "handlebox",
241 widget->allocation.x, widget->allocation.y,
242 widget->allocation.width, widget->allocation.height,
243 GTK_ORIENTATION_VERTICAL);
244 #endif
245
246 return FALSE;
247 }
248 #endif
249
250 static void
251 size_allocate_cb(GtkWidget *widget, GtkAllocation *allocation, gpointer user_data)
252 {
253 gint x, y;
254
255 #if GTK_CHECK_VERSION(2, 20, 0)
256 if (gtk_widget_get_mapped(widget)) {
257 #else
258 if (GTK_WIDGET_MAPPED(widget)) {
259 #endif
260 gtk_window_get_position(GTK_WINDOW(widget), &x, &y);
261 helper_win_set_position(widget, x, y);
262 }
263 }
264
265 static void
266 size_request_cb(GtkWidget *widget, GtkRequisition *req, gpointer data)
267 {
268
269 #if GTK_CHECK_VERSION(2, 20, 0)
270 if (gtk_widget_get_mapped(widget)) {
271 #else
272 if (GTK_WIDGET_MAPPED(widget)) {
273 #endif
274 gint width, height;
275 gtk_window_get_size(GTK_WINDOW(widget), &width, &height);
276
277 if (width > req->width) {
278 gtk_window_resize(GTK_WINDOW(widget), req->width, req->height);
279 }
280 }
281 }
282
283 int
284 main(int argc, char *argv[])
285 {
286 GtkWidget *toolbar;
287 GtkWidget *window;
288 GtkWidget *hbox;
289 GtkWidget *handle;
290 GtkWidget *frame;
291
292 setlocale(LC_ALL, "");
293 bindtextdomain(PACKAGE, LOCALEDIR);
294 textdomain(PACKAGE);
295 bind_textdomain_codeset(PACKAGE, "UTF-8");
296
297 uim_init();
298
299 gtk_init(&argc, &argv);
300
301 window = gtk_window_new(GTK_WINDOW_POPUP);
302
303 gtk_window_set_type_hint(GTK_WINDOW(window), GDK_WINDOW_TYPE_HINT_DOCK);
304
305 gtk_window_set_skip_taskbar_hint(GTK_WINDOW(window), TRUE);
306 gtk_window_set_decorated(GTK_WINDOW(window), FALSE);
307 gtk_window_stick(GTK_WINDOW(window));
308
309 gtk_widget_add_events(window, GDK_BUTTON_PRESS_MASK);
310
311 frame = gtk_frame_new(NULL);
312 gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_OUT);
313 gtk_container_add(GTK_CONTAINER(window), frame);
314
315 #if GTK_CHECK_VERSION(3, 2, 0)
316 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
317 #else
318 hbox = gtk_hbox_new(FALSE, 0);
319 #endif
320 gtk_container_add(GTK_CONTAINER(frame), hbox);
321
322 handle = gtk_drawing_area_new();
323 gtk_widget_set_size_request(handle, 8, -1);
324 gtk_box_pack_start(GTK_BOX(hbox), handle, FALSE, FALSE, 0);
325
326 toolbar = (GtkWidget*)uim_toolbar_standalone_new();
327 gtk_box_pack_start(GTK_BOX(hbox), toolbar, FALSE, FALSE, 0);
328
329 #if GTK_CHECK_VERSION(2, 90, 0)
330 g_signal_connect(G_OBJECT(handle), "draw",
331 G_CALLBACK(handle_draw_cb), NULL);
332 #else
333 g_signal_connect(G_OBJECT(handle), "expose-event",
334 G_CALLBACK(handle_expose_event_cb), NULL);
335 #endif
336
337 g_signal_connect(G_OBJECT(window), "delete_event",
338 G_CALLBACK(delete_event), NULL);
339 g_signal_connect(G_OBJECT(window), "button-press-event",
340 G_CALLBACK(button_press_event_cb), toolbar);
341 g_signal_connect(G_OBJECT(window), "button-release-event",
342 G_CALLBACK(button_release_event_cb), NULL);
343 g_signal_connect(G_OBJECT(window), "motion-notify-event",
344 G_CALLBACK(motion_notify_event_cb), NULL);
345 g_signal_connect(G_OBJECT(window), "size-allocate",
346 G_CALLBACK(size_allocate_cb), NULL);
347 #if !GTK_CHECK_VERSION(2, 90, 0)
348 g_signal_connect(G_OBJECT(window), "size-request",
349 G_CALLBACK(size_request_cb), NULL);
350 #endif
351
352 gtk_widget_show_all(GTK_WIDGET(window));
353
354 if (argc > 1) {
355 gint x, y;
356 if (!gtk_window_parse_geometry(GTK_WINDOW(window), argv[1])) {
357
358 #if GLIB_CHECK_VERSION(2, 6, 0)
359 parse_options(argc, argv);
360 #else
361 g_warning(_("Unable to parse the geometry string '%s'"), argv[1]);
362 #endif
363 }
364 gtk_window_get_position(GTK_WINDOW(window), &x, &y);
365 g_object_set_data(G_OBJECT(window), "position_x", GINT_TO_POINTER(x));
366 g_object_set_data(G_OBJECT(window), "position_y", GINT_TO_POINTER(y));
367 } else {
368 gint x, y, w, h, sc_w, sc_h;
369 gint panel_height = 32; /* FIXME! */
370
371 gtk_window_get_size(GTK_WINDOW(window), &w, &h);
372 sc_w = gdk_screen_width();
373 sc_h = gdk_screen_height();
374
375 x = sc_w - w;
376 y = sc_h - h - panel_height; /* FIXME! */
377 helper_win_set_position(window, x, y);
378 }
379
380 gtk_main();
381
382 uim_quit();
383
384 return 0;
385 }
386