JWM Source Documentation
confirm.c
Go to the documentation of this file.
1 
10 #include "jwm.h"
11 #include "confirm.h"
12 #include "client.h"
13 #include "font.h"
14 #include "button.h"
15 #include "border.h"
16 #include "screen.h"
17 #include "misc.h"
18 #include "settings.h"
19 #include "key.h"
20 
21 #ifndef DISABLE_CONFIRM
22 
24 typedef unsigned char DialogButtonState;
25 #define DBS_NORMAL 0
26 #define DBS_OK 1
27 #define DBS_CANCEL 2
29 typedef struct {
30 
31  int x, y;
32  int width, height;
34 
35  int okx;
36  int cancelx;
37  int buttony;
38  int buttonWidth, buttonHeight;
40 
41  int lineCount;
42  char **message;
43 
44  Pixmap pmap;
46 
47  void (*action)(ClientNode*);
48  Window client;
49 
50 } DialogType;
51 
52 static DialogType *dialog = NULL;
53 
54 static int minWidth = 0;
55 
56 static void RunDialogAction(void);
57 static void DestroyConfirmDialog(void);
58 static void ComputeDimensions(const ClientNode *np);
59 static void DrawDialog(void);
60 static void DrawButtons(void);
61 static void ExposeConfirmDialog(void);
62 static char HandleDialogExpose(const XExposeEvent *event);
63 static char HandleDialogButtonPress(const XButtonEvent *event);
64 static char HandleDialogButtonRelease(const XButtonEvent *event);
65 static char HandleDialogKeyPress(const XKeyEvent *event);
66 
67 static const char *GetOKString()
68 {
69  return _("OK");
70 }
71 
72 static const char *GetCancelString()
73 {
74  return _("Cancel");
75 }
76 
78 void ShutdownDialogs(void)
79 {
80  if(dialog) {
82  dialog = NULL;
83  }
84 }
85 
87 void RunDialogAction(void)
88 {
89  if(dialog->client == None) {
90  (dialog->action)(NULL);
91  } else {
92  ClientNode *np = FindClientByWindow(dialog->client);
93  if(np) {
94  (dialog->action)(np);
95  }
96  }
97 }
98 
100 char ProcessDialogEvent(const XEvent *event)
101 {
102 
103  Assert(event);
104 
105  switch(event->type) {
106  case Expose:
107  return HandleDialogExpose(&event->xexpose);
108  case ButtonPress:
109  return HandleDialogButtonPress(&event->xbutton);
110  case ButtonRelease:
111  return HandleDialogButtonRelease(&event->xbutton);
112  case KeyPress:
113  return HandleDialogKeyPress(&event->xkey);
114  default:
115  return 0;
116  }
117 
118 }
119 
121 char HandleDialogExpose(const XExposeEvent *event)
122 {
123  Assert(event);
124  if(dialog && dialog->node->window == event->window) {
126  return 1;
127  } else {
128  return 0;
129  }
130 }
131 
133 char HandleDialogButtonRelease(const XButtonEvent *event)
134 {
135 
136  Assert(event);
137 
138  if(dialog && event->window == dialog->node->window) {
139  char cancelPressed = 0;
140  char okPressed = 0;
141  const int y = event->y;
142  if(y >= dialog->buttony && y < dialog->buttony + dialog->buttonHeight) {
143  const int x = event->x;
144  if(x >= dialog->okx && x < dialog->okx + dialog->buttonWidth) {
145  okPressed = 1;
146  } else if(x >= dialog->cancelx
147  && x < dialog->cancelx + dialog->buttonWidth) {
148  cancelPressed = 1;
149  }
150  }
151 
152  if(okPressed) {
153  RunDialogAction();
154  }
155 
156  if(cancelPressed || okPressed) {
158  } else {
159  dialog->buttonState = DBS_NORMAL;
160  DrawButtons();
162  }
163 
164  return 1;
165  } else {
166 
167  if(dialog) {
168  if(dialog->buttonState != DBS_NORMAL) {
169  dialog->buttonState = DBS_NORMAL;
170  DrawButtons();
172  }
173  }
174 
175  return 0;
176 
177  }
178 
179 }
180 
182 char HandleDialogButtonPress(const XButtonEvent *event)
183 {
184 
185  Assert(event);
186 
187  /* Find the dialog on which the press occured (if any). */
188  if(dialog && event->window == dialog->node->window) {
189 
190  /* Determine which button was pressed (if any). */
191  char cancelPressed = 0;
192  char okPressed = 0;
193  const int y = event->y;
194  if(y >= dialog->buttony && y < dialog->buttony + dialog->buttonHeight) {
195  const int x = event->x;
196  if(x >= dialog->okx && x < dialog->okx + dialog->buttonWidth) {
197  okPressed = 1;
198  } else if(x >= dialog->cancelx
199  && x < dialog->cancelx + dialog->buttonWidth) {
200  cancelPressed = 1;
201  }
202  }
203 
204  dialog->buttonState = DBS_NORMAL;
205  if(cancelPressed) {
206  dialog->buttonState = DBS_CANCEL;
207  }
208 
209  if(okPressed) {
210  dialog->buttonState = DBS_OK;
211  }
212 
213  /* Draw the buttons. */
214  DrawButtons();
216 
217  return 1;
218 
219  } else {
220 
221  /* This event doesn't affect us. */
222  return 0;
223 
224  }
225 
226 }
227 
229 char HandleDialogKeyPress(const XKeyEvent *event)
230 {
231  if(dialog && event->window == dialog->node->window) {
232  KeyType key = GetKey(event);
233  switch(key & 0xFF) {
234  case KEY_ENTER:
235  RunDialogAction();
237  break;
238  case KEY_ESC:
240  break;
241  default:
242  break;
243  }
244  return 1;
245  } else {
246  return 0;
247  }
248 }
249 
251 void ShowConfirmDialog(ClientNode *np, void (*action)(ClientNode*), ...)
252 {
253 
254  va_list ap;
255  XSetWindowAttributes attrs;
256  XSizeHints shints;
257  Window window;
258  char *str;
259  int x;
260 
261  Assert(action);
262 
263  /* Only allow one dialog at a time. */
264  if(dialog) {
266  }
267 
268  dialog = Allocate(sizeof(DialogType));
269  dialog->client = np ? np->window : None;
270  dialog->action = action;
271  dialog->buttonState = DBS_NORMAL;
272 
273  /* Get the number of lines. */
274  va_start(ap, action);
275  for(dialog->lineCount = 0; va_arg(ap, char*); dialog->lineCount++);
276  va_end(ap);
277 
278  dialog->message = Allocate(dialog->lineCount * sizeof(char*));
279  va_start(ap, action);
280  for(x = 0; x < dialog->lineCount; x++) {
281  str = va_arg(ap, char*);
282  dialog->message[x] = CopyString(str);
283  }
284  va_end(ap);
285 
286  ComputeDimensions(np);
287 
288  /* Create the pixmap used for rendering. */
290  dialog->width, dialog->height,
291  rootDepth);
292 
293  /* Create the window. */
294  attrs.background_pixel = colors[COLOR_MENU_BG];
295  attrs.event_mask = ButtonPressMask
296  | ButtonReleaseMask
297  | KeyPressMask
298  | ExposureMask;
300  dialog->x, dialog->y,
301  dialog->width, dialog->height, 0,
302  CopyFromParent, InputOutput, CopyFromParent,
303  CWBackPixel | CWEventMask, &attrs);
304  shints.x = dialog->x;
305  shints.y = dialog->y;
306  shints.flags = PPosition;
307  JXSetWMNormalHints(display, window, &shints);
308  JXStoreName(display, window, _("Confirm"));
311 
312  /* Draw the dialog. */
313  DrawDialog();
314 
315  /* Add the client and give it focus. */
316  dialog->node = AddClientWindow(window, 0, 0);
317  Assert(dialog->node);
318  if(np) {
319  dialog->node->owner = np->window;
320  }
321  dialog->node->state.status |= STAT_WMDIALOG;
322  FocusClient(dialog->node);
323 
324  /* Grab the mouse. */
325  JXGrabButton(display, AnyButton, AnyModifier, window, True,
326  ButtonReleaseMask, GrabModeAsync, GrabModeAsync, None, None);
327 
328 
329 }
330 
333 {
334  Assert(dialog);
335  JXCopyArea(display, dialog->pmap, dialog->node->window, rootGC,
336  0, 0, dialog->width, dialog->height, 0, 0);
337 }
338 
341 {
342 
343  int x;
344 
345  Assert(dialog);
346 
347  /* This will take care of destroying the dialog window since
348  * its parent will be destroyed. */
349  RemoveClient(dialog->node);
350 
351  /* Free the pixmap. */
352  JXFreePixmap(display, dialog->pmap);
353 
354  /* Free the message. */
355  for(x = 0; x < dialog->lineCount; x++) {
356  Release(dialog->message[x]);
357  }
358  Release(dialog->message);
359 
360  Release(dialog);
361  dialog = NULL;
362 
363 }
364 
367 {
368 
369  const ScreenType *sp;
370  int width;
371  int x;
372 
373  Assert(dialog);
374 
375  /* Get the min width from the size of the buttons. */
376  if(!minWidth) {
378  width = GetStringWidth(FONT_MENU, GetOKString()) * 3;
379  if(width > minWidth) {
380  minWidth = width;
381  }
382  minWidth += 16 * 3;
383  }
384  dialog->width = minWidth;
385 
386  /* Take into account the size of the message. */
387  for(x = 0; x < dialog->lineCount; x++) {
388  width = GetStringWidth(FONT_MENU, dialog->message[x]);
389  if(width > dialog->width) {
390  dialog->width = width;
391  }
392  }
394  dialog->width += 8;
395  dialog->height = (dialog->lineCount + 2) * dialog->lineHeight;
396 
397  if(np) {
398 
399  dialog->x = np->x + (np->width - dialog->width) / 2;
400  dialog->y = np->y + (np->height - dialog->height) / 2;
401 
402  if(dialog->x < 0) {
403  dialog->x = 0;
404  }
405  if(dialog->y < 0) {
406  dialog->y = 0;
407  }
408  if(dialog->x + dialog->width >= rootWidth) {
409  dialog->x = rootWidth - dialog->width - (settings.borderWidth * 2);
410  }
411  if(dialog->y + dialog->height >= rootHeight) {
412  const unsigned titleHeight = GetTitleHeight();
413  dialog->y = rootHeight - dialog->height
414  - (settings.borderWidth * 2 + titleHeight);
415  }
416 
417  } else {
418 
419  sp = GetMouseScreen();
420 
421  dialog->x = (sp->width - dialog->width) / 2 + sp->x;
422  dialog->y = (sp->height - dialog->height) / 2 + sp->y;
423 
424  }
425 
426 }
427 
429 void DrawDialog(void)
430 {
431 
432  int yoffset;
433  int x;
434 
435  Assert(dialog);
436 
437  /* Clear the dialog. */
439  JXFillRectangle(display, dialog->pmap, rootGC, 0, 0,
440  dialog->width, dialog->height);
441 
442  /* Draw the message. */
443  yoffset = 4;
444  for(x = 0; x < dialog->lineCount; x++) {
446  4, yoffset, dialog->width, dialog->message[x]);
447  yoffset += dialog->lineHeight;
448  }
449 
450  /* Draw the buttons. */
451  DrawButtons();
452 
453 }
454 
456 void DrawButtons(void)
457 {
458 
459  ButtonNode button;
460  int temp;
461 
462  Assert(dialog);
463 
466  if(temp > dialog->buttonWidth) {
467  dialog->buttonWidth = temp;
468  }
469  dialog->buttonWidth += 16;
470  dialog->buttonHeight = dialog->lineHeight + 4;
471 
472  ResetButton(&button, dialog->pmap);
473  button.border = 1;
474  button.font = FONT_MENU;
475  button.width = dialog->buttonWidth;
476  button.height = dialog->buttonHeight;
477  button.alignment = ALIGN_CENTER;
478 
479  dialog->okx = dialog->width / 3 - dialog->buttonWidth / 2;
480  dialog->cancelx = 2 * dialog->width / 3 - dialog->buttonWidth / 2;
481  dialog->buttony = dialog->height - dialog->lineHeight
482  - dialog->lineHeight / 2;
483 
484  if(dialog->buttonState == DBS_OK) {
485  button.type = BUTTON_MENU_ACTIVE;
486  } else {
487  button.type = BUTTON_MENU;
488  }
489  button.text = GetOKString();
490  button.x = dialog->okx;
491  button.y = dialog->buttony;
492  DrawButton(&button);
493 
494  if(dialog->buttonState == DBS_CANCEL) {
495  button.type = BUTTON_MENU_ACTIVE;
496  } else {
497  button.type = BUTTON_MENU;
498  }
499  button.text = GetCancelString();
500  button.x = dialog->cancelx;
501  button.y = dialog->buttony;
502  DrawButton(&button);
503 
504 }
505 
506 #else /* DISABLE_CONFIRM */
507 
509 char ProcessDialogEvent(const XEvent *event)
510 {
511  return 0;
512 }
513 
515 void ShowConfirmDialog(ClientNode *np, void (*action)(ClientNode*), ...)
516 {
517  Assert(action);
518  (action)(np);
519 }
520 
521 #endif /* DISABLE_CONFIRM */
522 

joewing.net / Projects / JWM