| File: | demos/ctk-demo/event_axes.c |
| Warning: | line 594, column 50 Casting a non-structure type to a structure type and accessing a field can lead to memory access errors or data corruption |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* Touch and Drawing Tablets |
| 2 | * |
| 3 | * Demonstrates advanced handling of event information from exotic |
| 4 | * input devices. |
| 5 | * |
| 6 | * On one hand, this snippet demonstrates management of drawing tablets, |
| 7 | * those contain additional information for the pointer other than |
| 8 | * X/Y coordinates. Tablet pads events are mapped to actions, which |
| 9 | * are both defined and interpreted by the application. |
| 10 | * |
| 11 | * Input axes are dependent on hardware devices, on linux/unix you |
| 12 | * can see the device axes through xinput list <device>. Each time |
| 13 | * a different hardware device is used to move the pointer, the |
| 14 | * master device will be updated to match the axes it provides, |
| 15 | * these changes can be tracked through CdkDevice::changed, or |
| 16 | * checking cdk_event_get_source_device(). |
| 17 | * |
| 18 | * On the other hand, this demo handles basic multitouch events, |
| 19 | * each event coming from an specific touchpoint will contain a |
| 20 | * CdkEventSequence that's unique for its lifetime, so multiple |
| 21 | * touchpoints can be tracked. |
| 22 | */ |
| 23 | |
| 24 | #include <glib/gi18n.h> |
| 25 | #include <ctk/ctk.h> |
| 26 | |
| 27 | typedef struct { |
| 28 | CdkDevice *last_source; |
| 29 | CdkDeviceTool *last_tool; |
| 30 | gdouble *axes; |
| 31 | CdkRGBA color; |
| 32 | gdouble x; |
| 33 | gdouble y; |
| 34 | } AxesInfo; |
| 35 | |
| 36 | typedef struct { |
| 37 | GHashTable *pointer_info; /* CdkDevice -> AxesInfo */ |
| 38 | GHashTable *touch_info; /* CdkEventSequence -> AxesInfo */ |
| 39 | } EventData; |
| 40 | |
| 41 | const gchar *colors[] = { |
| 42 | "black", |
| 43 | "orchid", |
| 44 | "fuchsia", |
| 45 | "indigo", |
| 46 | "thistle", |
| 47 | "sienna", |
| 48 | "azure", |
| 49 | "plum", |
| 50 | "lime", |
| 51 | "navy", |
| 52 | "maroon", |
| 53 | "burlywood" |
| 54 | }; |
| 55 | |
| 56 | static CtkPadActionEntry pad_actions[] = { |
| 57 | { CTK_PAD_ACTION_BUTTON, 1, -1, N_("Nuclear strike")("Nuclear strike"), "pad.nuke" }, |
| 58 | { CTK_PAD_ACTION_BUTTON, 2, -1, N_("Release siberian methane reserves")("Release siberian methane reserves"), "pad.heat" }, |
| 59 | { CTK_PAD_ACTION_BUTTON, 3, -1, N_("Release solar flare")("Release solar flare"), "pad.fry" }, |
| 60 | { CTK_PAD_ACTION_BUTTON, 4, -1, N_("De-stabilize Oort cloud")("De-stabilize Oort cloud"), "pad.fall" }, |
| 61 | { CTK_PAD_ACTION_BUTTON, 5, -1, N_("Ignite WR-104")("Ignite WR-104"), "pad.burst" }, |
| 62 | { CTK_PAD_ACTION_BUTTON, 6, -1, N_("Lart whoever asks about this button")("Lart whoever asks about this button"), "pad.lart" }, |
| 63 | { CTK_PAD_ACTION_RING, -1, -1, N_("Earth axial tilt")("Earth axial tilt"), "pad.tilt" }, |
| 64 | { CTK_PAD_ACTION_STRIP, -1, -1, N_("Extent of weak nuclear force")("Extent of weak nuclear force"), "pad.dissolve" }, |
| 65 | }; |
| 66 | |
| 67 | static const gchar *pad_action_results[] = { |
| 68 | "☢", |
| 69 | "♨", |
| 70 | "☼", |
| 71 | "☄", |
| 72 | "⚡", |
| 73 | "💫", |
| 74 | "◑", |
| 75 | "⚛" |
| 76 | }; |
| 77 | |
| 78 | static guint cur_color = 0; |
| 79 | static guint pad_action_timeout_id = 0; |
| 80 | |
| 81 | static AxesInfo * |
| 82 | axes_info_new (void) |
| 83 | { |
| 84 | AxesInfo *info; |
| 85 | |
| 86 | info = g_new0 (AxesInfo, 1)((AxesInfo *) g_malloc0_n ((1), sizeof (AxesInfo))); |
| 87 | cdk_rgba_parse (&info->color, colors[cur_color]); |
| 88 | |
| 89 | cur_color = (cur_color + 1) % G_N_ELEMENTS (colors)(sizeof (colors) / sizeof ((colors)[0])); |
| 90 | |
| 91 | return info; |
| 92 | } |
| 93 | |
| 94 | static EventData * |
| 95 | event_data_new (void) |
| 96 | { |
| 97 | EventData *data; |
| 98 | |
| 99 | data = g_new0 (EventData, 1)((EventData *) g_malloc0_n ((1), sizeof (EventData))); |
| 100 | data->pointer_info = g_hash_table_new_full (NULL((void*)0), NULL((void*)0), NULL((void*)0), |
| 101 | (GDestroyNotify) g_free); |
| 102 | data->touch_info = g_hash_table_new_full (NULL((void*)0), NULL((void*)0), NULL((void*)0), |
| 103 | (GDestroyNotify) g_free); |
| 104 | |
| 105 | return data; |
| 106 | } |
| 107 | |
| 108 | static void |
| 109 | event_data_free (EventData *data) |
| 110 | { |
| 111 | g_hash_table_destroy (data->pointer_info); |
| 112 | g_hash_table_destroy (data->touch_info); |
| 113 | g_free (data); |
| 114 | } |
| 115 | |
| 116 | static void |
| 117 | update_axes_from_event (CdkEvent *event, |
| 118 | EventData *data) |
| 119 | { |
| 120 | CdkDevice *device, *source_device; |
| 121 | CdkEventSequence *sequence; |
| 122 | CdkDeviceTool *tool; |
| 123 | gdouble x, y; |
| 124 | AxesInfo *info; |
| 125 | |
| 126 | device = cdk_event_get_device (event); |
| 127 | source_device = cdk_event_get_source_device (event); |
| 128 | sequence = cdk_event_get_event_sequence (event); |
| 129 | tool = cdk_event_get_device_tool (event); |
| 130 | |
| 131 | if (event->type == CDK_TOUCH_END || |
| 132 | event->type == CDK_TOUCH_CANCEL) |
| 133 | { |
| 134 | g_hash_table_remove (data->touch_info, sequence); |
| 135 | return; |
| 136 | } |
| 137 | else if (event->type == CDK_LEAVE_NOTIFY) |
| 138 | { |
| 139 | g_hash_table_remove (data->pointer_info, device); |
| 140 | return; |
| 141 | } |
| 142 | |
| 143 | if (!sequence) |
| 144 | { |
| 145 | info = g_hash_table_lookup (data->pointer_info, device); |
| 146 | |
| 147 | if (!info) |
| 148 | { |
| 149 | info = axes_info_new (); |
| 150 | g_hash_table_insert (data->pointer_info, device, info); |
| 151 | } |
| 152 | } |
| 153 | else |
| 154 | { |
| 155 | info = g_hash_table_lookup (data->touch_info, sequence); |
| 156 | |
| 157 | if (!info) |
| 158 | { |
| 159 | info = axes_info_new (); |
| 160 | g_hash_table_insert (data->touch_info, sequence, info); |
| 161 | } |
| 162 | } |
| 163 | |
| 164 | if (info->last_source != source_device) |
| 165 | info->last_source = source_device; |
| 166 | |
| 167 | if (info->last_tool != tool) |
| 168 | info->last_tool = tool; |
| 169 | |
| 170 | g_clear_pointer (&info->axes, g_free)do { _Static_assert (sizeof *(&info->axes) == sizeof ( gpointer), "Expression evaluates to false"); __typeof__ ((& info->axes)) _pp = (&info->axes); __typeof__ (*(& info->axes)) _ptr = *_pp; *_pp = ((void*)0); if (_ptr) (g_free ) (_ptr); } while (0); |
| 171 | |
| 172 | if (event->type == CDK_TOUCH_BEGIN || |
| 173 | event->type == CDK_TOUCH_UPDATE) |
| 174 | { |
| 175 | if (sequence && event->touch.emulating_pointer) |
| 176 | g_hash_table_remove (data->pointer_info, device); |
| 177 | } |
| 178 | if (event->type == CDK_MOTION_NOTIFY) |
| 179 | { |
| 180 | info->axes = |
| 181 | g_memdup2 (event->motion.axes, |
| 182 | sizeof (gdouble) * cdk_device_get_n_axes (source_device)); |
| 183 | } |
| 184 | else if (event->type == CDK_BUTTON_PRESS || |
| 185 | event->type == CDK_BUTTON_RELEASE) |
| 186 | { |
| 187 | info->axes = |
| 188 | g_memdup2 (event->button.axes, |
| 189 | sizeof (gdouble) * cdk_device_get_n_axes (source_device)); |
| 190 | } |
| 191 | |
| 192 | if (cdk_event_get_coords (event, &x, &y)) |
| 193 | { |
| 194 | info->x = x; |
| 195 | info->y = y; |
| 196 | } |
| 197 | } |
| 198 | |
| 199 | static gboolean |
| 200 | event_cb (CtkWidget *widget, |
| 201 | CdkEvent *event, |
| 202 | gpointer user_data) |
| 203 | { |
| 204 | update_axes_from_event (event, user_data); |
| 205 | ctk_widget_queue_draw (widget); |
| 206 | return FALSE(0); |
| 207 | } |
| 208 | |
| 209 | static void |
| 210 | render_arrow (cairo_t *cr, |
| 211 | gdouble x_diff, |
| 212 | gdouble y_diff, |
| 213 | const gchar *label) |
| 214 | { |
| 215 | cairo_save (cr); |
| 216 | |
| 217 | cairo_set_source_rgb (cr, 0, 0, 0); |
| 218 | cairo_new_path (cr); |
| 219 | cairo_move_to (cr, 0, 0); |
| 220 | cairo_line_to (cr, x_diff, y_diff); |
| 221 | cairo_stroke (cr); |
| 222 | |
| 223 | cairo_move_to (cr, x_diff, y_diff); |
| 224 | cairo_show_text (cr, label); |
| 225 | |
| 226 | cairo_restore (cr); |
| 227 | } |
| 228 | |
| 229 | static void |
| 230 | draw_axes_info (cairo_t *cr, |
| 231 | AxesInfo *info, |
| 232 | CtkAllocation *allocation) |
| 233 | { |
| 234 | gdouble pressure, tilt_x, tilt_y, distance, wheel, rotation, slider; |
| 235 | CdkAxisFlags axes = cdk_device_get_axes (info->last_source); |
| 236 | |
| 237 | cairo_save (cr); |
| 238 | |
| 239 | cairo_set_line_width (cr, 1); |
| 240 | cdk_cairo_set_source_rgba (cr, &info->color); |
| 241 | |
| 242 | cairo_move_to (cr, 0, info->y); |
| 243 | cairo_line_to (cr, allocation->width, info->y); |
| 244 | cairo_move_to (cr, info->x, 0); |
| 245 | cairo_line_to (cr, info->x, allocation->height); |
| 246 | cairo_stroke (cr); |
| 247 | |
| 248 | cairo_translate (cr, info->x, info->y); |
| 249 | |
| 250 | if (!info->axes) |
| 251 | { |
| 252 | cairo_restore (cr); |
| 253 | return; |
| 254 | } |
| 255 | |
| 256 | if (axes & CDK_AXIS_FLAG_PRESSURE) |
| 257 | { |
| 258 | cairo_pattern_t *pattern; |
| 259 | |
| 260 | cdk_device_get_axis (info->last_source, info->axes, CDK_AXIS_PRESSURE, |
| 261 | &pressure); |
| 262 | |
| 263 | pattern = cairo_pattern_create_radial (0, 0, 0, 0, 0, 100); |
| 264 | cairo_pattern_add_color_stop_rgba (pattern, pressure, 1, 0, 0, pressure); |
| 265 | cairo_pattern_add_color_stop_rgba (pattern, 1, 0, 0, 1, 0); |
| 266 | |
| 267 | cairo_set_source (cr, pattern); |
| 268 | |
| 269 | cairo_arc (cr, 0, 0, 100, 0, 2 * G_PI3.1415926535897932384626433832795028841971693993751); |
| 270 | cairo_fill (cr); |
| 271 | |
| 272 | cairo_pattern_destroy (pattern); |
| 273 | } |
| 274 | |
| 275 | if (axes & CDK_AXIS_FLAG_XTILT && |
| 276 | axes & CDK_AXIS_FLAG_YTILT) |
| 277 | { |
| 278 | cdk_device_get_axis (info->last_source, info->axes, CDK_AXIS_XTILT, |
| 279 | &tilt_x); |
| 280 | cdk_device_get_axis (info->last_source, info->axes, CDK_AXIS_YTILT, |
| 281 | &tilt_y); |
| 282 | |
| 283 | render_arrow (cr, tilt_x * 100, tilt_y * 100, "Tilt"); |
| 284 | } |
| 285 | |
| 286 | if (axes & CDK_AXIS_FLAG_DISTANCE) |
| 287 | { |
| 288 | double dashes[] = { 5.0, 5.0 }; |
| 289 | cairo_text_extents_t extents; |
| 290 | |
| 291 | cdk_device_get_axis (info->last_source, info->axes, CDK_AXIS_DISTANCE, |
| 292 | &distance); |
| 293 | |
| 294 | cairo_save (cr); |
| 295 | |
| 296 | cairo_move_to (cr, distance * 100, 0); |
| 297 | |
| 298 | cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); |
| 299 | cairo_set_dash (cr, dashes, 2, 0.0); |
| 300 | cairo_arc (cr, 0, 0, distance * 100, 0, 2 * G_PI3.1415926535897932384626433832795028841971693993751); |
| 301 | cairo_stroke (cr); |
| 302 | |
| 303 | cairo_move_to (cr, 0, -distance * 100); |
| 304 | cairo_text_extents (cr, "Distance", &extents); |
| 305 | cairo_rel_move_to (cr, -extents.width / 2, 0); |
| 306 | cairo_show_text (cr, "Distance"); |
| 307 | |
| 308 | cairo_move_to (cr, 0, 0); |
| 309 | |
| 310 | cairo_restore (cr); |
| 311 | } |
| 312 | |
| 313 | if (axes & CDK_AXIS_FLAG_WHEEL) |
| 314 | { |
| 315 | cdk_device_get_axis (info->last_source, info->axes, CDK_AXIS_WHEEL, |
| 316 | &wheel); |
| 317 | |
| 318 | cairo_save (cr); |
| 319 | cairo_set_line_width (cr, 10); |
| 320 | cairo_set_source_rgba (cr, 0, 0, 0, 0.5); |
| 321 | |
| 322 | cairo_new_sub_path (cr); |
| 323 | cairo_arc (cr, 0, 0, 100, 0, wheel * 2 * G_PI3.1415926535897932384626433832795028841971693993751); |
| 324 | cairo_stroke (cr); |
| 325 | cairo_restore (cr); |
| 326 | } |
| 327 | |
| 328 | if (axes & CDK_AXIS_FLAG_ROTATION) |
| 329 | { |
| 330 | cdk_device_get_axis (info->last_source, info->axes, CDK_AXIS_ROTATION, |
| 331 | &rotation); |
| 332 | rotation *= 2 * G_PI3.1415926535897932384626433832795028841971693993751; |
| 333 | |
| 334 | cairo_save (cr); |
| 335 | cairo_rotate (cr, - G_PI3.1415926535897932384626433832795028841971693993751 / 2); |
| 336 | cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND); |
| 337 | cairo_set_line_width (cr, 5); |
| 338 | |
| 339 | cairo_new_sub_path (cr); |
| 340 | cairo_arc (cr, 0, 0, 100, 0, rotation); |
| 341 | cairo_stroke (cr); |
| 342 | cairo_restore (cr); |
| 343 | } |
| 344 | |
| 345 | if (axes & CDK_AXIS_FLAG_SLIDER) |
| 346 | { |
| 347 | cairo_pattern_t *pattern, *mask; |
| 348 | |
| 349 | cdk_device_get_axis (info->last_source, info->axes, CDK_AXIS_SLIDER, |
| 350 | &slider); |
| 351 | |
| 352 | cairo_save (cr); |
| 353 | |
| 354 | cairo_move_to (cr, 0, -10); |
| 355 | cairo_rel_line_to (cr, 0, -50); |
| 356 | cairo_rel_line_to (cr, 10, 0); |
| 357 | cairo_rel_line_to (cr, -5, 50); |
| 358 | cairo_close_path (cr); |
| 359 | |
| 360 | cairo_clip_preserve (cr); |
| 361 | |
| 362 | pattern = cairo_pattern_create_linear (0, -10, 0, -60); |
| 363 | cairo_pattern_add_color_stop_rgb (pattern, 0, 0, 1, 0); |
| 364 | cairo_pattern_add_color_stop_rgb (pattern, 1, 1, 0, 0); |
| 365 | cairo_set_source (cr, pattern); |
| 366 | cairo_pattern_destroy (pattern); |
| 367 | |
| 368 | mask = cairo_pattern_create_linear (0, -10, 0, -60); |
| 369 | cairo_pattern_add_color_stop_rgba (mask, 0, 0, 0, 0, 1); |
| 370 | cairo_pattern_add_color_stop_rgba (mask, slider, 0, 0, 0, 1); |
| 371 | cairo_pattern_add_color_stop_rgba (mask, slider, 0, 0, 0, 0); |
| 372 | cairo_pattern_add_color_stop_rgba (mask, 1, 0, 0, 0, 0); |
| 373 | cairo_mask (cr, mask); |
| 374 | cairo_pattern_destroy (mask); |
| 375 | |
| 376 | cairo_set_source_rgb (cr, 0, 0, 0); |
| 377 | cairo_stroke (cr); |
| 378 | |
| 379 | cairo_restore (cr); |
| 380 | } |
| 381 | |
| 382 | cairo_restore (cr); |
| 383 | } |
| 384 | |
| 385 | static const gchar * |
| 386 | tool_type_to_string (CdkDeviceToolType tool_type) |
| 387 | { |
| 388 | switch (tool_type) |
| 389 | { |
| 390 | case CDK_DEVICE_TOOL_TYPE_PEN: |
| 391 | return "Pen"; |
| 392 | case CDK_DEVICE_TOOL_TYPE_ERASER: |
| 393 | return "Eraser"; |
| 394 | case CDK_DEVICE_TOOL_TYPE_BRUSH: |
| 395 | return "Brush"; |
| 396 | case CDK_DEVICE_TOOL_TYPE_PENCIL: |
| 397 | return "Pencil"; |
| 398 | case CDK_DEVICE_TOOL_TYPE_AIRBRUSH: |
| 399 | return "Airbrush"; |
| 400 | case CDK_DEVICE_TOOL_TYPE_MOUSE: |
| 401 | return "Mouse"; |
| 402 | case CDK_DEVICE_TOOL_TYPE_LENS: |
| 403 | return "Lens cursor"; |
| 404 | case CDK_DEVICE_TOOL_TYPE_UNKNOWN: |
| 405 | default: |
| 406 | return "Unknown"; |
| 407 | } |
| 408 | } |
| 409 | |
| 410 | static void |
| 411 | draw_device_info (CtkWidget *widget, |
| 412 | cairo_t *cr, |
| 413 | CdkEventSequence *sequence, |
| 414 | gint *y, |
| 415 | AxesInfo *info) |
| 416 | { |
| 417 | PangoLayout *layout; |
| 418 | GString *string; |
| 419 | gint height; |
| 420 | |
| 421 | cairo_save (cr); |
| 422 | |
| 423 | string = g_string_new (NULL((void*)0)); |
| 424 | g_string_append_printf (string, "Source: %s", |
| 425 | cdk_device_get_name (info->last_source)); |
| 426 | |
| 427 | if (sequence) |
| 428 | g_string_append_printf (string, "\nSequence: %d", |
| 429 | GPOINTER_TO_UINT (sequence)((guint) (gulong) (sequence))); |
| 430 | |
| 431 | if (info->last_tool) |
| 432 | { |
| 433 | const gchar *tool_type; |
| 434 | guint64 serial; |
| 435 | |
| 436 | tool_type = tool_type_to_string (cdk_device_tool_get_tool_type (info->last_tool)); |
| 437 | serial = cdk_device_tool_get_serial (info->last_tool); |
| 438 | g_string_append_printf (string, "\nTool: %s", tool_type); |
| 439 | |
| 440 | if (serial != 0) |
| 441 | g_string_append_printf (string, ", Serial: %lx", serial); |
| 442 | } |
| 443 | |
| 444 | cairo_move_to (cr, 10, *y); |
| 445 | layout = ctk_widget_create_pango_layout (widget, string->str); |
| 446 | pango_cairo_show_layout (cr, layout); |
| 447 | cairo_stroke (cr); |
| 448 | |
| 449 | pango_layout_get_pixel_size (layout, NULL((void*)0), &height); |
| 450 | |
| 451 | cdk_cairo_set_source_rgba (cr, &info->color); |
| 452 | cairo_set_line_width (cr, 10); |
| 453 | cairo_move_to (cr, 0, *y); |
| 454 | |
| 455 | *y = *y + height; |
| 456 | cairo_line_to (cr, 0, *y); |
| 457 | cairo_stroke (cr); |
| 458 | |
| 459 | cairo_restore (cr); |
| 460 | |
| 461 | g_object_unref (layout); |
| 462 | g_string_free (string, TRUE)(__builtin_constant_p ((!(0))) ? (((!(0))) ? (g_string_free) ( (string), ((!(0)))) : g_string_free_and_steal (string)) : (g_string_free ) ((string), ((!(0))))); |
| 463 | } |
| 464 | |
| 465 | static gboolean |
| 466 | draw_cb (CtkWidget *widget, |
| 467 | cairo_t *cr, |
| 468 | gpointer user_data) |
| 469 | { |
| 470 | EventData *data = user_data; |
| 471 | CtkAllocation allocation; |
| 472 | AxesInfo *info; |
| 473 | GHashTableIter iter; |
| 474 | gpointer key, value; |
| 475 | gint y = 0; |
| 476 | |
| 477 | ctk_widget_get_allocation (widget, &allocation); |
| 478 | |
| 479 | /* Draw Abs info */ |
| 480 | g_hash_table_iter_init (&iter, data->pointer_info); |
| 481 | |
| 482 | while (g_hash_table_iter_next (&iter, NULL((void*)0), &value)) |
| 483 | { |
| 484 | info = value; |
| 485 | draw_axes_info (cr, info, &allocation); |
| 486 | } |
| 487 | |
| 488 | g_hash_table_iter_init (&iter, data->touch_info); |
| 489 | |
| 490 | while (g_hash_table_iter_next (&iter, NULL((void*)0), &value)) |
| 491 | { |
| 492 | info = value; |
| 493 | draw_axes_info (cr, info, &allocation); |
| 494 | } |
| 495 | |
| 496 | /* Draw name, color legend and misc data */ |
| 497 | g_hash_table_iter_init (&iter, data->pointer_info); |
| 498 | |
| 499 | while (g_hash_table_iter_next (&iter, NULL((void*)0), &value)) |
| 500 | { |
| 501 | info = value; |
| 502 | draw_device_info (widget, cr, NULL((void*)0), &y, info); |
| 503 | } |
| 504 | |
| 505 | g_hash_table_iter_init (&iter, data->touch_info); |
| 506 | |
| 507 | while (g_hash_table_iter_next (&iter, &key, &value)) |
| 508 | { |
| 509 | info = value; |
| 510 | draw_device_info (widget, cr, key, &y, info); |
| 511 | } |
| 512 | |
| 513 | return FALSE(0); |
| 514 | } |
| 515 | |
| 516 | static void |
| 517 | update_label_text (CtkWidget *label, |
| 518 | const gchar *text) |
| 519 | { |
| 520 | gchar *markup = NULL((void*)0); |
| 521 | |
| 522 | if (text) |
| 523 | markup = g_strdup_printf ("<span font='48.0'>%s</span>", text); |
| 524 | ctk_label_set_markup (CTK_LABEL (label)((((CtkLabel*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((label)), ((ctk_label_get_type ())))))), markup); |
| 525 | g_free (markup); |
| 526 | } |
| 527 | |
| 528 | static gboolean |
| 529 | reset_label_text_timeout_cb (gpointer user_data) |
| 530 | { |
| 531 | CtkWidget *label = user_data; |
| 532 | |
| 533 | update_label_text (label, NULL((void*)0)); |
| 534 | pad_action_timeout_id = 0; |
| 535 | return G_SOURCE_REMOVE(0); |
| 536 | } |
| 537 | |
| 538 | static void |
| 539 | update_label_and_timeout (CtkWidget *label, |
| 540 | const gchar *text) |
| 541 | { |
| 542 | if (pad_action_timeout_id) |
| 543 | g_source_remove (pad_action_timeout_id); |
| 544 | |
| 545 | update_label_text (label, text); |
| 546 | pad_action_timeout_id = g_timeout_add (200, reset_label_text_timeout_cb, label); |
| 547 | } |
| 548 | |
| 549 | static void |
| 550 | on_action_activate (GSimpleAction *action, |
| 551 | GVariant *parameter, |
| 552 | gpointer user_data) |
| 553 | { |
| 554 | CtkWidget *label = user_data; |
| 555 | const gchar *result; |
| 556 | |
| 557 | result = g_object_get_data (G_OBJECT (action)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((action)), (((GType) ((20) << (2)))))))), "action-result"); |
| 558 | |
| 559 | if (!parameter) |
| 560 | update_label_and_timeout (label, result); |
| 561 | else |
| 562 | { |
| 563 | gchar *str; |
| 564 | |
| 565 | str = g_strdup_printf ("%s %.2f", result, g_variant_get_double (parameter)); |
| 566 | update_label_and_timeout (label, str); |
| 567 | g_free (str); |
| 568 | } |
| 569 | } |
| 570 | |
| 571 | static void |
| 572 | init_pad_controller (CtkWidget *window, |
| 573 | CtkWidget *label) |
| 574 | { |
| 575 | CtkPadController *pad_controller; |
| 576 | GSimpleActionGroup *action_group; |
| 577 | GSimpleAction *action; |
| 578 | gint i; |
| 579 | |
| 580 | action_group = g_simple_action_group_new (); |
| 581 | pad_controller = ctk_pad_controller_new (CTK_WINDOW (window)((((CtkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((window)), ((ctk_window_get_type ())))))), |
| 582 | G_ACTION_GROUP (action_group)((((GActionGroup*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((action_group)), ((g_action_group_get_type ())))))), |
| 583 | NULL((void*)0)); |
| 584 | |
| 585 | for (i = 0; i < G_N_ELEMENTS (pad_actions)(sizeof (pad_actions) / sizeof ((pad_actions)[0])); i++) |
| 586 | { |
| 587 | if (pad_actions[i].type == CTK_PAD_ACTION_BUTTON) |
| 588 | { |
| 589 | action = g_simple_action_new (pad_actions[i].action_name, NULL((void*)0)); |
| 590 | } |
| 591 | else |
| 592 | { |
| 593 | action = g_simple_action_new_stateful (pad_actions[i].action_name, |
| 594 | G_VARIANT_TYPE_DOUBLE((const GVariantType *) "d"), NULL((void*)0)); |
Casting a non-structure type to a structure type and accessing a field can lead to memory access errors or data corruption | |
| 595 | } |
| 596 | |
| 597 | g_signal_connect (action, "activate",g_signal_connect_data ((action), ("activate"), (((GCallback) ( on_action_activate))), (label), ((void*)0), (GConnectFlags) 0 ) |
| 598 | G_CALLBACK (on_action_activate), label)g_signal_connect_data ((action), ("activate"), (((GCallback) ( on_action_activate))), (label), ((void*)0), (GConnectFlags) 0 ); |
| 599 | g_object_set_data (G_OBJECT (action)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((action)), (((GType) ((20) << (2)))))))), "action-result", |
| 600 | (gpointer) pad_action_results[i]); |
| 601 | g_action_map_add_action (G_ACTION_MAP (action_group)((((GActionMap*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((action_group)), ((g_action_map_get_type ())))))), G_ACTION (action)((((GAction*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((action)), ((g_action_get_type ()))))))); |
| 602 | g_object_unref (action); |
| 603 | } |
| 604 | |
| 605 | ctk_pad_controller_set_action_entries (pad_controller, pad_actions, |
| 606 | G_N_ELEMENTS (pad_actions)(sizeof (pad_actions) / sizeof ((pad_actions)[0]))); |
| 607 | g_object_set_data_full (G_OBJECT (window)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((window)), (((GType) ((20) << (2)))))))), "pad-controller", |
| 608 | pad_controller, g_object_unref); |
| 609 | |
| 610 | g_object_unref (action_group); |
| 611 | } |
| 612 | |
| 613 | CtkWidget * |
| 614 | do_event_axes (CtkWidget *toplevel G_GNUC_UNUSED__attribute__ ((__unused__))) |
| 615 | { |
| 616 | static CtkWidget *window = NULL((void*)0); |
| 617 | |
| 618 | if (!window) |
| 619 | { |
| 620 | EventData *event_data; |
| 621 | CtkWidget *box, *label; |
| 622 | |
| 623 | window = ctk_window_new (CTK_WINDOW_TOPLEVEL); |
| 624 | ctk_window_set_title (CTK_WINDOW (window)((((CtkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((window)), ((ctk_window_get_type ())))))), "Event Axes"); |
| 625 | ctk_window_set_default_size (CTK_WINDOW (window)((((CtkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((window)), ((ctk_window_get_type ())))))), 400, 400); |
| 626 | |
| 627 | g_signal_connect (window, "destroy",g_signal_connect_data ((window), ("destroy"), (((GCallback) ( ctk_widget_destroyed))), (&window), ((void*)0), (GConnectFlags ) 0) |
| 628 | G_CALLBACK (ctk_widget_destroyed), &window)g_signal_connect_data ((window), ("destroy"), (((GCallback) ( ctk_widget_destroyed))), (&window), ((void*)0), (GConnectFlags ) 0); |
| 629 | |
| 630 | box = ctk_event_box_new (); |
| 631 | ctk_container_add (CTK_CONTAINER (window)((((CtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((window)), ((ctk_container_get_type ())))))), box); |
| 632 | ctk_widget_set_support_multidevice (box, TRUE(!(0))); |
| 633 | ctk_widget_add_events (box, |
| 634 | CDK_POINTER_MOTION_MASK | |
| 635 | CDK_BUTTON_PRESS_MASK | |
| 636 | CDK_BUTTON_RELEASE_MASK | |
| 637 | CDK_SMOOTH_SCROLL_MASK | |
| 638 | CDK_ENTER_NOTIFY_MASK | |
| 639 | CDK_LEAVE_NOTIFY_MASK | |
| 640 | CDK_TOUCH_MASK); |
| 641 | |
| 642 | event_data = event_data_new (); |
| 643 | g_object_set_data_full (G_OBJECT (box)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((box)), (((GType) ((20) << (2)))))))), "ctk-demo-event-data", |
| 644 | event_data, (GDestroyNotify) event_data_free); |
| 645 | |
| 646 | g_signal_connect (box, "event",g_signal_connect_data ((box), ("event"), (((GCallback) (event_cb ))), (event_data), ((void*)0), (GConnectFlags) 0) |
| 647 | G_CALLBACK (event_cb), event_data)g_signal_connect_data ((box), ("event"), (((GCallback) (event_cb ))), (event_data), ((void*)0), (GConnectFlags) 0); |
| 648 | g_signal_connect (box, "draw",g_signal_connect_data ((box), ("draw"), (((GCallback) (draw_cb ))), (event_data), ((void*)0), (GConnectFlags) 0) |
| 649 | G_CALLBACK (draw_cb), event_data)g_signal_connect_data ((box), ("draw"), (((GCallback) (draw_cb ))), (event_data), ((void*)0), (GConnectFlags) 0); |
| 650 | |
| 651 | label = ctk_label_new (""); |
| 652 | ctk_label_set_use_markup (CTK_LABEL (label)((((CtkLabel*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((label)), ((ctk_label_get_type ())))))), TRUE(!(0))); |
| 653 | ctk_container_add (CTK_CONTAINER (box)((((CtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((box)), ((ctk_container_get_type ())))))), label); |
| 654 | |
| 655 | init_pad_controller (window, label); |
| 656 | } |
| 657 | |
| 658 | if (!ctk_widget_get_visible (window)) |
| 659 | ctk_widget_show_all (window); |
| 660 | else |
| 661 | ctk_widget_destroy (window); |
| 662 | |
| 663 | return window; |
| 664 | } |