Skip to content

Commit 014a1f8

Browse files
allefantSiegeLord
authored andcommitted
add DND support to X11
1 parent 6a3c7f8 commit 014a1f8

File tree

12 files changed

+635
-1
lines changed

12 files changed

+635
-1
lines changed

cmake/FileList.cmake

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ set(ALLEGRO_SRC_X_FILES
118118
src/x/xclipboard.c
119119
src/x/xcursor.c
120120
src/x/xdisplay.c
121+
src/x/xdnd.c
121122
src/x/xevents.c
122123
src/x/xfullscreen.c
123124
src/x/xglx_config.c

docs/src/refman/display.txt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,17 @@ ALLEGRO_GTK_TOPLEVEL
196196
ALLEGRO_GTK_TOPLEVEL is incompatible with ALLEGRO_FULLSCREEN.
197197
Since: 5.1.5
198198

199+
ALLEGRO_DRAG_AND_DROP
200+
: If a display is created with the ALLEGRO_DRAG_AND_DROP flag it will
201+
generate ALLEGRO_EVENT_DROP events when files or text are dropped over
202+
the display.
203+
204+
> *[Unstable API]:* This is an experimental feature and currently only works for
205+
the X11 backend.
206+
207+
Since: 5.2.9
208+
209+
199210
0 can be used for default values.
200211

201212
See also: [al_set_new_display_option], [al_get_display_option], [al_set_display_option]

docs/src/refman/events.txt

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -541,6 +541,43 @@ physical display. However, on iOS, a secondary physical display is supported.
541541
display.source (ALLEGRO_DISPLAY *)
542542
: The display which was disconnected.
543543

544+
### ALLEGRO_EVENT_DROP
545+
546+
If a display is created with the ALLEGRO_DRAG_AND_DROP flag it will
547+
generate ALLEGRO_EVENT_DROP events when files or text are dropped over
548+
the display.
549+
550+
drop.x (int)
551+
: X coordinate that something is being dragged to
552+
553+
drop.y (int)
554+
: Y coordinate that something is being dragged to
555+
556+
drop.text (char *)
557+
: the filename or text that was dropped - this will be NULL while the
558+
item is being dragged and only set at the final drop.
559+
560+
> *Note*: if the *text* field is not NULL ownership transfers to the event
561+
receiver and it must eventually be freed with al_free.
562+
563+
drop.is_file (bool)
564+
: if text is not NULL whether the text is a filename or just plain
565+
text.
566+
567+
drop.row (int)
568+
: if there is multiple files or multiple rows of text this will
569+
number them, starting with 0.
570+
571+
drop.is_complete (bool)
572+
: indicates that this event will be the last one sent for the drag&drop
573+
action. If *is_complete* is set before receiving an event
574+
where *text* was not NULL it means the user aborted the drag&drop.
575+
576+
Since: 5.2.9
577+
578+
> *[Unstable API]:* This is an experimental feature and currently only works for
579+
the X11 backend.
580+
544581
## API: ALLEGRO_USER_EVENT
545582

546583
An event structure that can be emitted by user event sources.

examples/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ example(ex_depth_target ${IMAGE} ${FONT} ${COLOR} ${PRIM})
140140
example(ex_disable_screensaver ${FONT})
141141
example(ex_display_events ${FONT} ${PRIM})
142142
example(ex_display_options ${FONT} ${PRIM})
143+
example(ex_drag_and_drop ${IMAGE} ${FONT} ${TTF} ${COLOR} ${PRIM})
143144
example(ex_draw ${FONT} ${IMAGE} ${COLOR} ${PRIM} ${DATA_IMAGES})
144145
example(ex_draw_bitmap ${IMAGE} ${FONT} ${DATA_IMAGES})
145146
example(ex_drawpixels)

examples/ex_drag_and_drop.c

Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,200 @@
1+
/* ______ ___ ___
2+
* /\ _ \ /\_ \ /\_ \
3+
* \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___
4+
* \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\
5+
* \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \
6+
* \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/
7+
* \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/
8+
* /\____/
9+
* \_/__/
10+
*
11+
* System drag&drop example.
12+
*
13+
* This example shows how an Allegro window can receive pictures
14+
* (and text) from other applications.
15+
*
16+
* See readme.txt for copyright information.
17+
*/
18+
#define ALLEGRO_UNSTABLE
19+
#include <allegro5/allegro.h>
20+
#include <allegro5/allegro_font.h>
21+
#include <allegro5/allegro_ttf.h>
22+
#include <allegro5/allegro_color.h>
23+
#include <allegro5/allegro_image.h>
24+
#include <allegro5/allegro_primitives.h>
25+
26+
#include "common.c"
27+
28+
// We only accept up to 25 lines of text or files at a time.
29+
typedef struct Cell {
30+
char *rows[25];
31+
ALLEGRO_BITMAP *bitmap;
32+
} Cell;
33+
34+
int main(int argc, char **argv)
35+
{
36+
ALLEGRO_DISPLAY *display;
37+
ALLEGRO_TIMER *timer;
38+
ALLEGRO_EVENT_QUEUE *queue;
39+
ALLEGRO_FONT *font;
40+
bool done = false;
41+
bool redraw = true;
42+
int xdiv = 3;
43+
int ydiv = 4;
44+
Cell grid[xdiv * ydiv];
45+
int drop_x = -1;
46+
int drop_y = -1;
47+
48+
(void)argc;
49+
(void)argv;
50+
51+
// Initialize everything to NULL
52+
for (int i = 0; i < xdiv * ydiv; i++) {
53+
grid[i].rows[0] = strdup("drop file or text here");
54+
for (int r = 1; r < 25; r++) grid[i].rows[r] = NULL;
55+
grid[i].bitmap = NULL;
56+
}
57+
58+
if (!al_init()) {
59+
abort_example("Failed to init Allegro.\n");
60+
}
61+
al_init_image_addon();
62+
al_init_primitives_addon();
63+
al_init_font_addon();
64+
al_init_ttf_addon();
65+
init_platform_specific();
66+
ALLEGRO_MONITOR_INFO info;
67+
al_get_monitor_info(0, &info);
68+
// Make the window half as wide as the desktop and 4:3 aspect
69+
int w = (info.x2 - info.x1) / 2;
70+
int h = w * 3 / 4;
71+
72+
// Turn on drag/drop support
73+
al_set_new_display_flags(ALLEGRO_DRAG_AND_DROP);
74+
display = al_create_display(w, h);
75+
if (!display) {
76+
abort_example("Error creating display.\n");
77+
}
78+
79+
if (!al_install_keyboard()) {
80+
abort_example("Error installing keyboard.\n");
81+
}
82+
83+
font = al_load_font("data/DejaVuSans.ttf", 20, 0);
84+
if (!font) {
85+
abort_example("Could not load font.\n");
86+
}
87+
88+
timer = al_create_timer(1 / 60.0);
89+
90+
queue = al_create_event_queue();
91+
al_register_event_source(queue, al_get_keyboard_event_source());
92+
al_register_event_source(queue, al_get_timer_event_source(timer));
93+
// drag&drop events will come from the display, if enabled
94+
al_register_event_source(queue, al_get_display_event_source(display));
95+
96+
al_start_timer(timer);
97+
98+
while (!done) {
99+
ALLEGRO_EVENT event;
100+
101+
int fh = al_get_font_line_height(font);
102+
103+
if (redraw && al_is_event_queue_empty(queue)) {
104+
// draw a grid with the dropped text rows or files
105+
ALLEGRO_COLOR c1 = al_color_name("gainsboro");
106+
ALLEGRO_COLOR c2 = al_color_name("orange");
107+
al_clear_to_color(al_map_rgb_f(0, 0, 0));
108+
for (int y = 0; y < ydiv; y++) {
109+
for (int x = 0; x < xdiv; x++) {
110+
int gx = x * w / xdiv;
111+
int gy = y * h / ydiv;
112+
if (grid[x + y * xdiv].bitmap) {
113+
ALLEGRO_BITMAP *bmp = grid[x + y * xdiv].bitmap;
114+
float bw = al_get_bitmap_width(bmp);
115+
float bh = al_get_bitmap_height(bmp);
116+
float s = w / xdiv / bw;
117+
if (s > (h / ydiv - fh) / bh) s = (h / ydiv - fh) / bh;
118+
al_draw_scaled_bitmap(bmp, 0, 0, bw, bh, gx, gy + fh, bw * s, bh * s, 0);
119+
}
120+
for (int r = 0; r < 25; r++) {
121+
if (!grid[x + y * xdiv].rows[r]) break;
122+
al_draw_textf(font, c1, gx, gy + r * fh,
123+
0, "%s", grid[x + y * xdiv].rows[r]);
124+
}
125+
if (drop_x >= gx && drop_x < gx + w / xdiv &&
126+
drop_y >= gy && drop_y < gy + h / ydiv) {
127+
al_draw_rectangle(gx, gy, gx + w / xdiv, gy + h / ydiv, c2, 2);
128+
}
129+
else {
130+
al_draw_rectangle(gx, gy, gx + w / xdiv, gy + h / ydiv, c1, 0);
131+
}
132+
}
133+
}
134+
al_flip_display();
135+
redraw = false;
136+
}
137+
138+
al_wait_for_event(queue, &event);
139+
switch (event.type) {
140+
case ALLEGRO_EVENT_KEY_DOWN:
141+
if (event.keyboard.keycode == ALLEGRO_KEY_ESCAPE) {
142+
done = true;
143+
}
144+
break;
145+
146+
case ALLEGRO_EVENT_DISPLAY_CLOSE:
147+
done = true;
148+
break;
149+
150+
case ALLEGRO_EVENT_TIMER:
151+
redraw = true;
152+
break;
153+
154+
case ALLEGRO_EVENT_DROP:
155+
drop_x = event.drop.x;
156+
drop_y = event.drop.y;
157+
int col = drop_x * xdiv / w;
158+
int row = drop_y * ydiv / h;
159+
int i = col + row * xdiv;
160+
if (event.drop.text) {
161+
if (event.drop.row == 0) {
162+
// clear the previous contents of the cell
163+
for (int r = 0; r < 25; r++) {
164+
if (grid[i].rows[r]) {
165+
al_free(grid[i].rows[r]);
166+
grid[i].rows[r] = NULL;
167+
}
168+
}
169+
// insert the first row/file
170+
grid[i].rows[0] = event.drop.text;
171+
if (event.drop.is_file) {
172+
// if a file, try and load it as a bitmap to display
173+
if (grid[i].bitmap) al_destroy_bitmap(grid[i].bitmap);
174+
grid[i].bitmap = al_load_bitmap(grid[i].rows[0]);
175+
}
176+
}
177+
else {
178+
if (event.drop.row < 25) {
179+
grid[i].rows[event.drop.row] = event.drop.text;
180+
}
181+
else {
182+
al_free(event.drop.text);
183+
}
184+
}
185+
}
186+
if (event.drop.is_complete) {
187+
// stop highlighting a cell when the drop is completed
188+
drop_x = -1;
189+
drop_y = -1;
190+
}
191+
break;
192+
}
193+
}
194+
195+
al_destroy_font(font);
196+
197+
return 0;
198+
}
199+
200+
/* vim: set sts=3 sw=3 et: */

include/allegro5/display.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ enum {
2929
ALLEGRO_OPENGL_ES_PROFILE = 1 << 14,
3030
#if defined(ALLEGRO_UNSTABLE) || defined(ALLEGRO_INTERNAL_UNSTABLE) || defined(ALLEGRO_SRC)
3131
ALLEGRO_OPENGL_CORE_PROFILE = 1 << 15,
32+
ALLEGRO_DRAG_AND_DROP = 1 << 16,
3233
#endif
3334
};
3435

include/allegro5/events.h

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,9 @@ enum
4949
ALLEGRO_EVENT_TOUCH_CANCEL = 53,
5050

5151
ALLEGRO_EVENT_DISPLAY_CONNECTED = 60,
52-
ALLEGRO_EVENT_DISPLAY_DISCONNECTED = 61
52+
ALLEGRO_EVENT_DISPLAY_DISCONNECTED = 61,
53+
54+
ALLEGRO_EVENT_DROP = 62,
5355
};
5456

5557

@@ -197,6 +199,18 @@ struct ALLEGRO_USER_EVENT
197199

198200

199201

202+
typedef struct ALLEGRO_DROP_EVENT
203+
{
204+
_AL_EVENT_HEADER(struct ALLEGRO_DISPLAY)
205+
int x, y;
206+
int row;
207+
bool is_file;
208+
char *text;
209+
bool is_complete;
210+
} ALLEGRO_DROP_EVENT;
211+
212+
213+
200214
/* Type: ALLEGRO_EVENT
201215
*/
202216
typedef union ALLEGRO_EVENT ALLEGRO_EVENT;
@@ -217,6 +231,7 @@ union ALLEGRO_EVENT
217231
ALLEGRO_TIMER_EVENT timer;
218232
ALLEGRO_TOUCH_EVENT touch;
219233
ALLEGRO_USER_EVENT user;
234+
ALLEGRO_DROP_EVENT drop;
220235
};
221236

222237

include/allegro5/internal/aintern_xsystem.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#endif
1919

2020
#include "allegro5/internal/aintern_system.h"
21+
#include "allegro5/internal/aintern_xdnd.h"
2122

2223
/* This is our version of ALLEGRO_SYSTEM with driver specific extra data. */
2324
struct ALLEGRO_SYSTEM_XGLX
@@ -49,6 +50,9 @@ struct ALLEGRO_SYSTEM_XGLX
4950
Atom AllegroAtom;
5051
Atom XEmbedAtom;
5152

53+
/* drag and drop support */
54+
DndInfo dnd_info;
55+
5256
/* Background thread to process X events.
5357
* Not used if GTK main loop is used.
5458
*/

src/x/xdisplay.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include "allegro5/internal/aintern_xsystem.h"
1212
#include "allegro5/internal/aintern_xtouch.h"
1313
#include "allegro5/internal/aintern_xwindow.h"
14+
#include "allegro5/internal/aintern_xdnd.h"
1415
#include "allegro5/platform/aintxglx.h"
1516

1617
#include <X11/Xatom.h>
@@ -252,6 +253,10 @@ static bool xdpy_create_display_window(ALLEGRO_SYSTEM_XGLX *system,
252253
_al_xwin_set_frame(display, false);
253254
}
254255

256+
if (display->flags & ALLEGRO_DRAG_AND_DROP) {
257+
_al_xwin_accept_drag_and_drop(display, true);
258+
}
259+
255260
ALLEGRO_DEBUG("X11 window created.\n");
256261

257262
/* Set the PID related to the window. */

0 commit comments

Comments
 (0)