blob: 03abab2619c97370f8e66c599602d06c229b0729 [file] [log] [blame]
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001/*
2 * Copyright © 2012 Openismus GmbH
Jan Arne Petersen4c265182012-09-09 23:08:30 +02003 * Copyright © 2012 Intel Corporation
Jan Arne Petersencba9e472012-06-21 21:52:19 +02004 *
5 * Permission to use, copy, modify, distribute, and sell this software and
6 * its documentation for any purpose is hereby granted without fee, provided
7 * that the above copyright notice appear in all copies and that both that
8 * copyright notice and this permission notice appear in supporting
9 * documentation, and that the name of the copyright holders not be used in
10 * advertising or publicity pertaining to distribution of the software
11 * without specific, written prior permission. The copyright holders make
12 * no representations about the suitability of this software for any
13 * purpose. It is provided "as is" without express or implied warranty.
14 *
15 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
16 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
17 * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
18 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
19 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
20 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
21 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22 */
23
Philipp Brüschweiler591cfca2012-07-11 22:25:29 +020024#include <assert.h>
Jan Arne Petersencba9e472012-06-21 21:52:19 +020025#include <stdio.h>
26#include <stdlib.h>
27#include <string.h>
28
29#include <linux/input.h>
30#include <cairo.h>
31
32#include "window.h"
33#include "text-client-protocol.h"
34
Jan Arne Petersenb9eb02c2012-09-09 23:08:35 +020035static const char *font_name = "sans-serif";
36static int font_size = 14;
37
38struct text_layout {
39 cairo_glyph_t *glyphs;
40 int num_glyphs;
41 cairo_text_cluster_t *clusters;
42 int num_clusters;
43 cairo_text_cluster_flags_t cluster_flags;
44 cairo_scaled_font_t *font;
45};
46
Jan Arne Petersencba9e472012-06-21 21:52:19 +020047struct text_entry {
48 struct widget *widget;
Jan Arne Petersene829adc2012-08-10 16:47:22 +020049 struct window *window;
Jan Arne Petersencba9e472012-06-21 21:52:19 +020050 char *text;
51 int active;
Jan Arne Petersencba9e472012-06-21 21:52:19 +020052 struct text_model *model;
Jan Arne Petersenb9eb02c2012-09-09 23:08:35 +020053 struct text_layout *layout;
Jan Arne Petersencba9e472012-06-21 21:52:19 +020054};
55
56struct editor {
Jan Arne Petersen51963742012-08-10 16:47:20 +020057 struct text_model_factory *text_model_factory;
Jan Arne Petersencba9e472012-06-21 21:52:19 +020058 struct display *display;
59 struct window *window;
60 struct widget *widget;
61 struct text_entry *entry;
62 struct text_entry *editor;
63};
64
Jan Arne Petersenb9eb02c2012-09-09 23:08:35 +020065static struct text_layout *
66text_layout_create(void)
67{
68 struct text_layout *layout;
69 cairo_surface_t *surface;
70 cairo_t *cr;
71
72 layout = malloc(sizeof *layout);
73 if (!layout)
74 return NULL;
75
76 layout->glyphs = NULL;
77 layout->num_glyphs = 0;
78
79 layout->clusters = NULL;
80 layout->num_clusters = 0;
81
82 surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 0, 0);
83 cr = cairo_create(surface);
84 cairo_set_font_size(cr, font_size);
85 cairo_select_font_face(cr, font_name, CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
86 layout->font = cairo_get_scaled_font(cr);
87 cairo_scaled_font_reference(layout->font);
88
89 cairo_destroy(cr);
90 cairo_surface_destroy(surface);
91
92 return layout;
93}
94
95static void
96text_layout_destroy(struct text_layout *layout)
97{
98 if (layout->glyphs)
99 cairo_glyph_free(layout->glyphs);
100
101 if (layout->clusters)
102 cairo_text_cluster_free(layout->clusters);
103
104 cairo_scaled_font_destroy(layout->font);
105
106 free(layout);
107}
108
109static void
110text_layout_set_text(struct text_layout *layout,
111 const char *text)
112{
113 if (layout->glyphs)
114 cairo_glyph_free(layout->glyphs);
115
116 if (layout->clusters)
117 cairo_text_cluster_free(layout->clusters);
118
119 layout->glyphs = NULL;
120 layout->num_glyphs = 0;
121 layout->clusters = NULL;
122 layout->num_clusters = 0;
123
124 cairo_scaled_font_text_to_glyphs(layout->font, 0, 0, text, -1,
125 &layout->glyphs, &layout->num_glyphs,
126 &layout->clusters, &layout->num_clusters,
127 &layout->cluster_flags);
128}
129
130static void
131text_layout_draw(struct text_layout *layout, cairo_t *cr)
132{
133 cairo_save(cr);
134 cairo_set_scaled_font(cr, layout->font);
135 cairo_show_glyphs(cr, layout->glyphs, layout->num_glyphs);
136 cairo_restore(cr);
137}
138
139
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200140static void text_entry_redraw_handler(struct widget *widget, void *data);
141static void text_entry_button_handler(struct widget *widget,
142 struct input *input, uint32_t time,
143 uint32_t button,
144 enum wl_pointer_button_state state, void *data);
145
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200146static void
147text_entry_append(struct text_entry *entry, const char *text)
148{
149 entry->text = realloc(entry->text, strlen(entry->text) + strlen(text) + 1);
150 strcat(entry->text, text);
Jan Arne Petersenb9eb02c2012-09-09 23:08:35 +0200151 text_layout_set_text(entry->layout, entry->text);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200152}
153
154
155static void
156text_model_commit_string(void *data,
157 struct text_model *text_model,
158 const char *text,
159 uint32_t index)
160{
161 struct text_entry *entry = data;
162
163 text_entry_append(entry, text);
164
165 widget_schedule_redraw(entry->widget);
166}
167
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200168static void
169text_model_preedit_string(void *data,
170 struct text_model *text_model,
171 const char *text,
172 uint32_t index)
173{
174}
175
176static void
177text_model_preedit_styling(void *data,
178 struct text_model *text_model)
179{
180}
181
182static void
183text_model_key(void *data,
184 struct text_model *text_model)
185{
186}
187
188static void
189text_model_selection_replacement(void *data,
190 struct text_model *text_model)
191{
192}
193
194static void
195text_model_direction(void *data,
196 struct text_model *text_model)
197{
198}
199
200static void
201text_model_locale(void *data,
202 struct text_model *text_model)
203{
204}
205
Jan Arne Petersende3b6a12012-08-10 16:47:21 +0200206static void
207text_model_activated(void *data,
208 struct text_model *text_model)
209{
210 struct text_entry *entry = data;
211
212 entry->active = 1;
213
214 widget_schedule_redraw(entry->widget);
215}
216
217static void
218text_model_deactivated(void *data,
219 struct text_model *text_model)
220{
221 struct text_entry *entry = data;
222
223 entry->active = 0;
224
225 widget_schedule_redraw(entry->widget);
226}
227
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200228static const struct text_model_listener text_model_listener = {
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200229 text_model_commit_string,
230 text_model_preedit_string,
231 text_model_preedit_styling,
232 text_model_key,
233 text_model_selection_replacement,
234 text_model_direction,
Jan Arne Petersende3b6a12012-08-10 16:47:21 +0200235 text_model_locale,
236 text_model_activated,
237 text_model_deactivated
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200238};
239
240static struct text_entry*
241text_entry_create(struct editor *editor, const char *text)
242{
243 struct text_entry *entry;
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200244
245 entry = malloc(sizeof *entry);
246
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200247 entry->widget = widget_add_widget(editor->widget, entry);
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200248 entry->window = editor->window;
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200249 entry->text = strdup(text);
250 entry->active = 0;
Jan Arne Petersen4c265182012-09-09 23:08:30 +0200251 entry->model = text_model_factory_create_text_model(editor->text_model_factory);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200252 text_model_add_listener(entry->model, &text_model_listener, entry);
253
Jan Arne Petersenb9eb02c2012-09-09 23:08:35 +0200254 entry->layout = text_layout_create();
255 text_layout_set_text(entry->layout, entry->text);
256
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200257 widget_set_redraw_handler(entry->widget, text_entry_redraw_handler);
258 widget_set_button_handler(entry->widget, text_entry_button_handler);
259
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200260 return entry;
261}
262
263static void
264text_entry_destroy(struct text_entry *entry)
265{
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200266 widget_destroy(entry->widget);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200267 text_model_destroy(entry->model);
Jan Arne Petersenb9eb02c2012-09-09 23:08:35 +0200268 text_layout_destroy(entry->layout);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200269 free(entry->text);
270 free(entry);
271}
272
273static void
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200274redraw_handler(struct widget *widget, void *data)
275{
276 struct editor *editor = data;
277 cairo_surface_t *surface;
278 struct rectangle allocation;
279 cairo_t *cr;
280
281 surface = window_get_surface(editor->window);
282 widget_get_allocation(editor->widget, &allocation);
283
284 cr = cairo_create(surface);
285 cairo_rectangle(cr, allocation.x, allocation.y, allocation.width, allocation.height);
286 cairo_clip(cr);
287
288 cairo_translate(cr, allocation.x, allocation.y);
289
290 /* Draw background */
291 cairo_push_group(cr);
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200292 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200293 cairo_set_source_rgba(cr, 1, 1, 1, 1);
294 cairo_rectangle(cr, 0, 0, allocation.width, allocation.height);
295 cairo_fill(cr);
296
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200297 cairo_pop_group_to_source(cr);
298 cairo_paint(cr);
299
300 cairo_destroy(cr);
301 cairo_surface_destroy(surface);
302}
303
304static void
305text_entry_allocate(struct text_entry *entry, int32_t x, int32_t y,
306 int32_t width, int32_t height)
307{
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200308 widget_set_allocation(entry->widget, x, y, width, height);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200309}
310
311static void
312resize_handler(struct widget *widget,
313 int32_t width, int32_t height, void *data)
314{
315 struct editor *editor = data;
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200316 struct rectangle allocation;
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200317
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200318 widget_get_allocation(editor->widget, &allocation);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200319
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200320 text_entry_allocate(editor->entry,
321 allocation.x + 20, allocation.y + 20,
322 width - 40, height / 2 - 40);
323 text_entry_allocate(editor->editor,
324 allocation.x + 20, allocation.y + height / 2 + 20,
325 width - 40, height / 2 - 40);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200326}
327
328static void
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200329text_entry_activate(struct text_entry *entry,
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200330 struct wl_seat *seat)
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200331{
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200332 struct wl_surface *surface = window_get_wl_surface(entry->window);
333
334 text_model_activate(entry->model,
335 seat,
336 surface);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200337}
338
339static void
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200340text_entry_deactivate(struct text_entry *entry,
341 struct wl_seat *seat)
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200342{
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200343 text_model_deactivate(entry->model,
344 seat);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200345}
346
347static void
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200348text_entry_redraw_handler(struct widget *widget, void *data)
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200349{
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200350 struct text_entry *entry = data;
351 cairo_surface_t *surface;
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200352 struct rectangle allocation;
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200353 cairo_t *cr;
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200354
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200355 surface = window_get_surface(entry->window);
356 widget_get_allocation(entry->widget, &allocation);
357
358 cr = cairo_create(surface);
359 cairo_rectangle(cr, allocation.x, allocation.y, allocation.width, allocation.height);
360 cairo_clip(cr);
361
362 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
363
364 cairo_push_group(cr);
365 cairo_translate(cr, allocation.x, allocation.y);
366
367 cairo_set_source_rgba(cr, 1, 1, 1, 1);
368 cairo_rectangle(cr, 0, 0, allocation.width, allocation.height);
369 cairo_fill(cr);
370
371 cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
372
373 if (entry->active) {
374 cairo_rectangle(cr, 0, 0, allocation.width, allocation.height);
375 cairo_set_line_width (cr, 3);
376 cairo_set_source_rgba(cr, 0, 0, 1, 1.0);
377 cairo_stroke(cr);
378 }
379
380 cairo_set_source_rgba(cr, 0, 0, 0, 1);
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200381
382 cairo_translate(cr, 10, allocation.height / 2);
Jan Arne Petersenb9eb02c2012-09-09 23:08:35 +0200383 text_layout_draw(entry->layout, cr);
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200384 cairo_pop_group_to_source(cr);
385 cairo_paint(cr);
386
387 cairo_destroy(cr);
388 cairo_surface_destroy(surface);
389}
390
391static void
392text_entry_button_handler(struct widget *widget,
393 struct input *input, uint32_t time,
394 uint32_t button,
395 enum wl_pointer_button_state state, void *data)
396{
397 struct text_entry *entry = data;
398
399 if (button != BTN_LEFT) {
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200400 return;
401 }
402
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200403 if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
404 struct wl_seat *seat = input_get_seat(input);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200405
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200406 text_entry_activate(entry, seat);
407 }
408}
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200409
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200410static void
411editor_button_handler(struct widget *widget,
412 struct input *input, uint32_t time,
413 uint32_t button,
414 enum wl_pointer_button_state state, void *data)
415{
416 struct editor *editor = data;
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200417
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200418 if (button != BTN_LEFT) {
419 return;
420 }
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200421
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200422 if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
423 struct wl_seat *seat = input_get_seat(input);
424
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200425 text_entry_deactivate(editor->entry, seat);
426 text_entry_deactivate(editor->editor, seat);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200427 }
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200428}
429
430static void
431global_handler(struct wl_display *display, uint32_t id,
432 const char *interface, uint32_t version, void *data)
433{
434 struct editor *editor = data;
435
Jan Arne Petersen51963742012-08-10 16:47:20 +0200436 if (!strcmp(interface, "text_model_factory")) {
437 editor->text_model_factory = wl_display_bind(display, id,
438 &text_model_factory_interface);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200439 }
440}
441
442int
443main(int argc, char *argv[])
444{
445 struct editor editor;
446
447 editor.display = display_create(argc, argv);
448 if (editor.display == NULL) {
449 fprintf(stderr, "failed to create display: %m\n");
450 return -1;
451 }
452 wl_display_add_global_listener(display_get_display(editor.display),
453 global_handler, &editor);
454
455
456 editor.window = window_create(editor.display);
457 editor.widget = frame_create(editor.window, &editor);
458
459 editor.entry = text_entry_create(&editor, "Entry");
460 editor.editor = text_entry_create(&editor, "Editor");
461
462 window_set_title(editor.window, "Text Editor");
463
464 widget_set_redraw_handler(editor.widget, redraw_handler);
465 widget_set_resize_handler(editor.widget, resize_handler);
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200466 widget_set_button_handler(editor.widget, editor_button_handler);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200467
468 window_schedule_resize(editor.window, 500, 400);
469
470 display_run(editor.display);
471
472 text_entry_destroy(editor.entry);
473 text_entry_destroy(editor.editor);
474
475 return 0;
476}