libxputty  0.1
A damn tiny abstraction Layer to create X11 window/widgets with cairo surfaces
xmessage-dialog.c
Go to the documentation of this file.
1 /*
2  * 0BSD
3  *
4  * BSD Zero Clause License
5  *
6  * Copyright (c) 2019 Hermann Meyer
7  *
8  * Permission to use, copy, modify, and/or distribute this software for any
9  * purpose with or without fee is hereby granted.
10 
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
12  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13  * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
14  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
16  * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17  * PERFORMANCE OF THIS SOFTWARE.
18  *
19  */
20 
21 #include "xmessage-dialog.h"
22 
23 
24 static void draw_message_label(Widget_t *w, int width, int height) {
26  cairo_text_extents_t extents;
28  cairo_set_font_size (w->crb, 12.0);
29  int i = 0;
30  for(;i<(int)mb->lin;i++) {
31  cairo_text_extents(w->crb,mb->message[i] , &extents);
32  cairo_move_to (w->crb, 100, ((40)+(extents.height * (2*i))));
33  cairo_show_text(w->crb, mb->message[i]);
34  cairo_new_path (w->crb);
35  }
36 }
37 
38 static void draw_message_window(void *w_, void* user_data) {
39  Widget_t *w = (Widget_t*)w_;
40  XWindowAttributes attrs;
41  XGetWindowAttributes(w->app->dpy, (Window)w->widget, &attrs);
42  int width_t = attrs.width;
43  int height_t = attrs.height;
44  if (attrs.map_state != IsViewable) return;
45 
46  cairo_rectangle(w->crb,0,0,width_t,height_t);
48  cairo_fill (w->crb);
49 
51  int width = cairo_xlib_surface_get_width(w->image);
52  int height = cairo_xlib_surface_get_height(w->image);
53  double x = 64.0/(double)(width);
54  double y = 64.0/(double)height;
55  double x1 = (double)height/64.0;
56  double y1 = (double)(width)/64.0;
57  cairo_scale(w->crb, x,y);
58  cairo_set_source_surface (w->crb, w->image, 50, 50);
59  cairo_rectangle(w->crb,50, 50, width, height);
60  cairo_fill(w->crb);
61  cairo_scale(w->crb, x1,y1);
62 
63  draw_message_label(w,width_t,height_t);
65 }
66 
67 static void draw_entry(void *w_, void* user_data) {
68  Widget_t *w = (Widget_t*)w_;
69  if (!w) return;
70  XWindowAttributes attrs;
71  XGetWindowAttributes(w->app->dpy, (Window)w->widget, &attrs);
72  int width = attrs.width;
73  int height = attrs.height;
74  if (attrs.map_state != IsViewable) return;
75 
77  cairo_rectangle(w->cr,0,0,width,height);
78  cairo_fill_preserve (w->cr);
80  cairo_set_line_width(w->cr, 2.0);
81  cairo_stroke(w->cr);
82 
83  cairo_set_font_size (w->cr, 9.0);
84 
85  cairo_move_to (w->cr, 2, 9);
86  cairo_show_text(w->cr, " ");
87 }
88 
89 static void entry_add_text(void *w_, void *label_) {
90  Widget_t *w = (Widget_t*)w_;
91  if (!w) return;
92  char *label = (char*)label_;
93  if (!label) {
94  label = (char*)"";
95  }
96  draw_entry(w,NULL);
97  cairo_text_extents_t extents;
99  cairo_set_font_size (w->cr, 11.0);
100  if (strlen( w->input_label))
101  w->input_label[strlen( w->input_label)-1] = 0;
102  if (strlen( w->input_label)<30) {
103  if (strlen(label))
104  strcat( w->input_label, label);
105  }
106  w->label = w->input_label;
107  strcat( w->input_label, "|");
108  cairo_set_font_size (w->cr, 12.0);
109  cairo_text_extents(w->cr, w->input_label , &extents);
110 
111  cairo_move_to (w->cr, 2, 12.0+extents.height);
112  cairo_show_text(w->cr, w->input_label);
113 
114 }
115 
116 static void entry_clip(Widget_t *w) {
117  draw_entry(w,NULL);
118  cairo_text_extents_t extents;
120  cairo_set_font_size (w->cr, 11.0);
121 
122  // check for UTF 8 char
123  if (strlen( w->input_label)>=2) {
124  int i = strlen( w->input_label)-1;
125  int j = 0;
126  int u = 0;
127  for(;i>0;i--) {
128  if(IS_UTF8(w->input_label[i])) {
129  u++;
130  }
131  j++;
132  if (u == 1) break;
133  if (j>2) break;
134  }
135  if (!u) j =2;
136 
137  memset(&w->input_label[strlen( w->input_label)-(sizeof(char)*(j))],0,sizeof(char)*(j));
138  strcat( w->input_label, "|");
139  }
140  cairo_set_font_size (w->cr, 12.0);
141  cairo_text_extents(w->cr, w->input_label , &extents);
142 
143  cairo_move_to (w->cr, 2, 12.0+extents.height);
144  cairo_show_text(w->cr, w->input_label);
145 
146 }
147 
148 static void message_okay_callback(void *w_, void* user_data) {
149  Widget_t *w = (Widget_t*)w_;
150  if (w->flags & HAS_POINTER && !*(int*)user_data){
151  Widget_t *p = (Widget_t*)w->parent;
152  MessageBox *mb = (MessageBox *)p->parent_struct;
153  if(mb->message_type == QUESTION_BOX || mb->message_type == SELECTION_BOX) {
154  Widget_t *pa = (Widget_t*)p->parent;
155  pa->func.dialog_callback(pa,&mb->response);
156  } else if(mb->message_type == ENTRY_BOX) {
157  Widget_t *pa = (Widget_t*)p->parent;
158  if (strlen( mb->text_entry->input_label))
159  mb->text_entry->input_label[strlen( mb->text_entry->input_label)-1] = 0;
161  pa->func.dialog_callback(pa,&mb->text_entry->label);
162  }
163  destroy_widget(p, p->app);
164  }
165 }
166 
167 static void message_no_callback(void *w_, void* user_data) {
168  Widget_t *w = (Widget_t*)w_;
169  if (w->flags & HAS_POINTER && !*(int*)user_data){
170  Widget_t *p = (Widget_t*)w->parent;
171  MessageBox *mb = (MessageBox *)p->parent_struct;
172  if(mb->message_type == QUESTION_BOX) {
173  Widget_t *pa = (Widget_t*)p->parent;
174  mb->response = -1;
175  pa->func.dialog_callback(pa,&mb->response);
176  }
177  destroy_widget(p, p->app);
178  }
179 }
180 
181 static void radio_box_set_active(Widget_t *w) {
182  Widget_t * p = (Widget_t*)w->parent;
183  MessageBox *mb = (MessageBox *)p->parent_struct;
184  int response = 0;
185  int i = 0;
186  for(;i<p->childlist->elem;i++) {
187  Widget_t *wid = p->childlist->childs[i];
188  if (wid->adj && wid->flags & IS_RADIO) {
189  ++response;
190  if (wid != w) adj_set_value(wid->adj_y, 0.0);
191  else if (wid == w) mb->response = response;
192  }
193  }
194 }
195 
196 static void radio_box_button_pressed(void *w_, void* button_, void* user_data) {
197  Widget_t *w = (Widget_t*)w_;
198  if (w->flags & HAS_FOCUS) {
199  radio_box_set_active(w);
200  }
201 }
202 
203 static void create_checkboxes(Widget_t *w) {
204  MessageBox *mb = (MessageBox *)w->parent_struct;
205  int y = (mb->lin + 1) * 24 +12;
206  int i = 0;
207  for(;i<(int)mb->sel;i++) {
208  Widget_t *wid = add_check_box(w,mb->choices[i] , 100, y + (24*i), 15, 15);
209  wid->flags |= IS_RADIO;
210  wid->func.button_press_callback = radio_box_button_pressed;
211  }
212 }
213 
214 static void entry_get_text(void *w_, void *key_, void *user_data) {
215  Widget_t *w = (Widget_t*)w_;
216  if (!w) return;
217  XKeyEvent *key = (XKeyEvent*)key_;
218  if (!key) return;
219  int nk = key_mapping(w->app->dpy, key);
220  if (nk) {
221  switch (nk) {
222  case 10:
223  {
224  Widget_t *p = (Widget_t*)w->parent;
225  MessageBox *mb = (MessageBox *)p->parent_struct;
226  Widget_t *pa = (Widget_t*)p->parent;
227  if (strlen( mb->text_entry->input_label))
228  mb->text_entry->input_label[strlen( mb->text_entry->input_label)-1] = 0;
230  pa->func.dialog_callback(pa,&mb->text_entry->label);
231 
232  destroy_widget(p, p->app);
233  }
234  break;
235  case 11: entry_clip(w);
236  break;
237  default:
238  break;
239  }
240  } else {
241  Status status;
242  KeySym keysym;
243  char buf[32];
244  Xutf8LookupString(w->xic, key, buf, sizeof(buf) - 1, &keysym, &status);
245  if(status == XLookupChars || status == XLookupBoth){
246  entry_add_text(w, buf);
247  }
248  }
249 }
250 
251 static void create_entry_box(Widget_t *w) {
252  MessageBox *mb = (MessageBox *)w->parent_struct;
253 
254  mb->text_entry = create_widget(w->app, w, 20, mb->height-90, mb->width-40, 40);
255  memset(mb->text_entry->input_label, 0, 32 * (sizeof mb->text_entry->input_label[0]) );
256  mb->text_entry->func.expose_callback = entry_add_text;
257  mb->text_entry->func.key_press_callback = entry_get_text;
260 }
261 
262 static void check_for_message(MessageBox *mb, const char *message) {
263  if(!message) return;
264  if(!strlen(message)) return;
265  int len = 0;
266  char *ms =strdup(message);
267  char * p = strtok (ms, "|");
268  while (p) {
269  mb->message = (char**)realloc (mb->message, sizeof (char*) * ++mb->lin);
270  mb->message[mb->lin-1] = strdup(p);
271  len = max(len, (int)strlen(mb->message[mb->lin-1]));
272  p = strtok (NULL, "|");
273  }
274  free(ms);
275  mb->width = len*12 ;
276  mb->height = mb->lin*12+150;
277 }
278 
279 static void check_for_choices(MessageBox *mb, const char *choices) {
280  if(!choices) return;
281  if(!strlen(choices)) return;
282  int len = 0;
283  char *ms =strdup(choices);
284  char * p = strtok (ms, "|");
285  while (p) {
286  mb->choices = (char**)realloc (mb->choices, sizeof (char*) * ++mb->sel);
287  mb->choices[mb->sel-1] = strdup(p);
288  len = max(len, (int)strlen(mb->choices[mb->sel-1]));
289  p = strtok (NULL, "|");
290  }
291  free(ms);
292  mb->width = max(len*12,(int)mb->width);
293  mb->height += mb->sel*12+50;
294 }
295 
296 static void check_for_style(MessageBox *mb, int style) {
297  if(style == ENTRY_BOX) {
298  mb->width = max(330,mb->width);
299  mb->height = max(140,mb->height+60);
300  }
301 }
302 
303 static void mg_mem_free(void *w_, void* user_data) {
304  Widget_t *w = (Widget_t*)w_;
305  MessageBox *mb = (MessageBox *)w->parent_struct;
306  if(mb->icon) {
307  XFreePixmap(w->app->dpy, (*mb->icon));
308  mb->icon = NULL;
309  }
310  int i = 0;
311  for(;i<(int)mb->lin;i++) {
312  free(mb->message[i]);
313  }
314  i = 0;
315  for(;i<(int)mb->sel;i++) {
316  free(mb->choices[i]);
317  }
318  free(mb->choices);
319  free(mb);
320 }
321 
322 Widget_t *open_message_dialog(Widget_t *w, int style, const char *title,
323  const char *message, const char *choices) {
324 
325  MessageBox *mb = (MessageBox*)malloc(sizeof(MessageBox));
326  mb->response = 0;
327  mb->message_type = 0;
328  mb->lin = 0;
329  mb->width = 330;
330  mb->height = 200;
331  mb->message = NULL;
332  mb->sel = 0;
333  mb->choices = NULL;
334  mb->icon = NULL;
335  check_for_message(mb, message);
336  check_for_choices(mb, choices);
337  check_for_style(mb, style);
338  Widget_t *wid = create_window(w->app, DefaultRootWindow(w->app->dpy), 0, 0, mb->width, mb->height);
339  wid->label = message;
340  wid->flags |= HAS_MEM;
341  wid->scale.gravity = CENTER;
342  wid->parent_struct = mb;
343  wid->parent = w;
344  wid->func.mem_free_callback = mg_mem_free;
345  wid->func.expose_callback = draw_message_window;
346  char *alternate_title = NULL;
347  char *button_title = (char*)"OK";
348  Widget_t *no;
349  switch (style) {
350  case INFO_BOX:
351  widget_get_png(wid, LDVAR(info_png));
352  alternate_title = (char*)"INFO";
353  mb->message_type = INFO_BOX;
355  break;
356  case WARNING_BOX:
357  widget_get_png(wid, LDVAR(warning_png));
358  alternate_title = (char*)"WARNING";
361  break;
362  case ERROR_BOX:
363  widget_get_png(wid, LDVAR(error_png));
364  alternate_title = (char*)"ERROR";
365  mb->message_type = ERROR_BOX;
367  break;
368  case QUESTION_BOX:
369  widget_get_png(wid, LDVAR(question_png));
370  alternate_title = (char*)"QUESTION";
371  no = add_button(wid, "NO", 10, mb->height-40, 60, 30);
372  no->scale.gravity = CENTER;
373  no->func.value_changed_callback = message_no_callback;
375  button_title = (char*)"YES";
377  break;
378  case SELECTION_BOX:
379  widget_get_png(wid, LDVAR(choice_png));
380  alternate_title = (char*)"SELECTION";
382  create_checkboxes(wid);
384  break;
385  case ENTRY_BOX:
386  widget_get_png(wid, LDVAR(message_png));
387  alternate_title = (char*)"TEXT ENTRY";
388  mb->message_type = ENTRY_BOX;
389  create_entry_box(wid);
391  break;
392  }
393  widget_set_title(wid, (title)? title : alternate_title);
394 
395  Widget_t *okay = add_button(wid, button_title, mb->width-70, mb->height-40, 60, 30);
396  okay->scale.gravity = CENTER;
397  okay->func.value_changed_callback = message_okay_callback;
398 
399  widget_show_all(wid);
400  return wid;
401 }
use_text_color_scheme
void use_text_color_scheme(Widget_t *w, Color_state st)
use_text_color_scheme - use text Colors to paint on Widget_t
Definition: xcolor.c:199
QUESTION_BOX
@ QUESTION_BOX
Definition: xmessage-dialog.h:36
Resize_t::gravity
Gravity gravity
Definition: xwidget.h:192
MessageBox::message
char ** message
Definition: xmessage-dialog.h:49
widget_set_title
void widget_set_title(Widget_t *w, const char *title)
widget_set_title - set window title for a Widget_t
Definition: xwidget.c:387
Widget_t::image
cairo_surface_t * image
Definition: xwidget.h:320
open_message_dialog
Widget_t * open_message_dialog(Widget_t *w, int style, const char *title, const char *message, const char *choices)
open_message_dialog - open a non blocking dialog window, lines in message chould be separated by the ...
Definition: xmessage-dialog.c:322
MessageBox::width
unsigned int width
Definition: xmessage-dialog.h:44
widget_set_icon_from_surface
void widget_set_icon_from_surface(Widget_t *w, Pixmap *icon_, cairo_surface_t *image)
widget_set_icon_from_surface - set icon image from cairo surface for Widget_t those icon will be used...
Definition: xpngloader.c:98
key_mapping
int key_mapping(Display *dpy, XKeyEvent *xkey)
_key_mapping - modifier key's mapped to a integer value
Definition: xwidget.c:26
Widget_t::parent_struct
void * parent_struct
Definition: xwidget.h:306
Childlist_t::childs
Widget_t ** childs
Definition: xchildlist.h:51
MessageBox::sel
unsigned int sel
Definition: xmessage-dialog.h:50
widget_set_scale
void widget_set_scale(Widget_t *w)
widget_set_scale - set scaling mode to scale a image surface to the size of the Widget_t surface
Definition: xwidget.c:141
create_widget
Widget_t * create_widget(Xputty *app, Widget_t *win, int x, int y, int width, int height)
*create_widget - create a widget A Widget_t could only be created as child of a other Widget_t To...
Definition: xwidget.c:268
Func_t::expose_callback
xevfunc expose_callback
Definition: xwidget.h:80
CENTER
@ CENTER
Definition: xwidget.h:165
HAS_POINTER
@ HAS_POINTER
Definition: xwidget.h:247
Widget_t::crb
cairo_t * crb
Definition: xwidget.h:318
HAS_FOCUS
@ HAS_FOCUS
Definition: xwidget.h:245
xmessage-dialog.h
ERROR_BOX
@ ERROR_BOX
Definition: xmessage-dialog.h:35
Widget_t::flags
long long flags
Definition: xwidget.h:324
adj_set_value
void adj_set_value(Adjustment_t *adj, float value)
adj_set_value - set the current value to the Adjustment_t
Definition: xadjustment.c:163
Widget_t::adj
Adjustment_t * adj
Definition: xwidget.h:334
use_fg_color_scheme
void use_fg_color_scheme(Widget_t *w, Color_state st)
use_fg_color_scheme - use forground Colors to paint on Widget_t
Definition: xcolor.c:178
Widget_t::cr
cairo_t * cr
Definition: xwidget.h:314
Widget_t::scale
Resize_t scale
Definition: xwidget.h:356
BACKGROUND_
@ BACKGROUND_
Definition: xcolor.h:53
Func_t::key_press_callback
evfunc key_press_callback
Definition: xwidget.h:96
add_check_box
Widget_t * add_check_box(Widget_t *parent, const char *label, int x, int y, int width, int height)
add_check_box - add a check box to a Widget_t connect to func.value_changed_callback to implement you...
Definition: xbutton.c:125
WARNING_BOX
@ WARNING_BOX
Definition: xmessage-dialog.h:34
HAS_MEM
@ HAS_MEM
Definition: xwidget.h:251
Widget_t::app
Xputty * app
Definition: xwidget.h:300
MessageBox
Definition: xmessage-dialog.h:41
Func_t::button_press_callback
evfunc button_press_callback
Definition: xwidget.h:93
Xputty::dpy
Display * dpy
Definition: xputty.h:181
USE_TRANSPARENCY
@ USE_TRANSPARENCY
Definition: xwidget.h:243
IS_RADIO
@ IS_RADIO
Definition: xwidget.h:239
widget_get_png
void widget_get_png(Widget_t *w, const unsigned char *name)
widget_get_png - read png into Widget_t xlib surface
Definition: xpngloader.c:41
INFO_BOX
@ INFO_BOX
Definition: xmessage-dialog.h:33
Widget_t::widget
Window widget
Definition: xwidget.h:302
XColor_t::selected
Colors selected
Definition: xcolor.h:91
Widget_t
Widget_t - struct to hold the basic Widget_t info.
Definition: xwidget.h:298
NORMAL_
@ NORMAL_
Definition: xcolor.h:39
MessageBox::height
unsigned int height
Definition: xmessage-dialog.h:45
MessageBox::choices
char ** choices
Definition: xmessage-dialog.h:51
LDVAR
#define LDVAR(NAME)
Definition: xpngloader.h:71
widget_reset_scale
void widget_reset_scale(Widget_t *w)
widget_reset_scale - used to reset scaling mode after a image surface is drawn to the Widget_t surfac...
Definition: xwidget.c:137
Widget_t::xic
XIC xic
Definition: xwidget.h:338
MessageBox::text_entry
Widget_t * text_entry
Definition: xmessage-dialog.h:47
destroy_widget
void destroy_widget(Widget_t *w, Xputty *main)
destroy_widget - destroy a widget When a Widget_t receive a destroy_widget() call,...
Definition: xwidget.c:71
Func_t::mem_free_callback
xevfunc mem_free_callback
Definition: xwidget.h:87
Widget_t::childlist
Childlist_t * childlist
Definition: xwidget.h:336
create_window
Widget_t * create_window(Xputty *app, Window win, int x, int y, int width, int height)
*create_window - create a Window You need to create as least minimun one Window to get started....
Definition: xwidget.c:145
ENTRY_BOX
@ ENTRY_BOX
Definition: xmessage-dialog.h:38
Childlist_t::elem
int elem
Definition: xchildlist.h:57
IS_UTF8
#define IS_UTF8(c)
IS_UTF8 - check if a char contain UTF 8 formated signs.
Definition: xputty.h:99
Widget_t::input_label
char input_label[32]
Definition: xwidget.h:328
set_pattern
void set_pattern(Widget_t *w, Colors *from, Colors *to, Color_mod mod)
set_pattern - set pattern for the selected Colors
Definition: xcolor.c:227
Widget_t::adj_y
Adjustment_t * adj_y
Definition: xwidget.h:332
Widget_t::func
Func_t func
Definition: xwidget.h:310
MessageBox::response
int response
Definition: xmessage-dialog.h:42
MessageBox::message_type
int message_type
Definition: xmessage-dialog.h:43
Xputty::color_scheme
XColor_t * color_scheme
Definition: xputty.h:183
MessageBox::lin
unsigned int lin
Definition: xmessage-dialog.h:46
max
#define max(x, y)
max - set a minimal value (x) as return value
Definition: xputty.h:86
Widget_t::parent
void * parent
Definition: xwidget.h:304
MessageBox::icon
Pixmap * icon
Definition: xmessage-dialog.h:48
use_base_color_scheme
void use_base_color_scheme(Widget_t *w, Color_state st)
use_base_color_scheme - use base Colors to paint on Widget_t
Definition: xcolor.c:192
SELECTION_BOX
@ SELECTION_BOX
Definition: xmessage-dialog.h:37
Widget_t::label
const char * label
Definition: xwidget.h:326
Func_t::value_changed_callback
xevfunc value_changed_callback
Definition: xwidget.h:85
add_button
Widget_t * add_button(Widget_t *parent, const char *label, int x, int y, int width, int height)
add_button - add a button to a Widget_t connect to func.value_changed_callback to implement your acti...
Definition: xbutton.c:26
XColor_t::normal
Colors normal
Definition: xcolor.h:89
widget_show_all
void widget_show_all(Widget_t *w)
widget_show_all - map/show Widget_t with all childs
Definition: xwidget.c:405
Func_t::dialog_callback
xevfunc dialog_callback
Definition: xwidget.h:91