]> Dogcows Code - chaz/homebank/blob - src/gtk-dateentry.c
import homebank-5.1.2
[chaz/homebank] / src / gtk-dateentry.c
1 /* HomeBank -- Free, easy, personal accounting for everyone.
2 * Copyright (C) 1995-2016 Maxime DOYEN
3 *
4 * This file is part of HomeBank.
5 *
6 * HomeBank is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * HomeBank is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include <stdlib.h>
21 #include <string.h>
22 #include <time.h>
23
24 #include <gtk/gtk.h>
25 #include <gdk/gdkkeysyms.h>
26
27 #include "gtk-dateentry.h"
28
29 #define MYDEBUG 0
30
31 #if MYDEBUG
32 #define DB(x) (x);
33 #else
34 #define DB(x);
35 #endif
36
37 enum {
38 CHANGED,
39 LAST_SIGNAL
40 };
41
42 enum {
43 PROPERTY_DATE = 5,
44 };
45
46 static void gtk_date_entry_dispose (GObject *gobject);
47 static void gtk_date_entry_finalize (GObject *gobject);
48 static void gtk_date_entry_destroy (GtkWidget *dateentry);
49
50 static void gtk_date_entry_entry_activate(GtkWidget * calendar, gpointer user_data);
51 static gint gtk_date_entry_entry_key_pressed (GtkWidget *widget, GdkEventKey *event, gpointer user_data);
52 static void gtk_date_entry_button_clicked (GtkWidget * widget, GtkDateEntry * dateentry);
53
54 static void
55 gtk_date_entry_popup(GtkDateEntry * dateentry, GdkEvent *event);
56
57 static gint gtk_date_entry_popup_key_event (GtkWidget *widget, GdkEventKey *event, gpointer user_data);
58 static gint gtk_date_entry_popup_button_press (GtkWidget * widget, GdkEvent * event, gpointer data);
59
60 static void gtk_date_entry_calendar_year(GtkWidget * calendar, GtkDateEntry * dateentry);
61 static void gtk_date_entry_calendar_getfrom(GtkWidget * calendar, GtkDateEntry * dateentry);
62 static gint gtk_date_entry_calendar_select(GtkWidget * calendar, gpointer user_data);
63
64
65 static void gtk_date_entry_entry_set_text(GtkDateEntry * dateentry);
66 static void gtk_date_entry_popdown(GtkDateEntry *dateentry);
67
68
69
70 static guint dateentry_signals[LAST_SIGNAL] = {0,};
71
72
73 // todo:finish this
74 // this is to be able to seizure d or d/m or m/d in the gtkdateentry
75
76 /* order of these in the current locale */
77 static GDateDMY dmy_order[3] =
78 {
79 G_DATE_DAY, G_DATE_MONTH, G_DATE_YEAR
80 };
81
82 struct _GDateParseTokens {
83 gint num_ints;
84 gint n[3];
85 guint month;
86 };
87
88 typedef struct _GDateParseTokens GDateParseTokens;
89
90 #define NUM_LEN 10
91
92 static void
93 hb_date_fill_parse_tokens (const gchar *str, GDateParseTokens *pt)
94 {
95 gchar num[4][NUM_LEN+1];
96 gint i;
97 const guchar *s;
98
99 DB( g_print("\n[dateentry] fill parse token\n") );
100
101 /* We count 4, but store 3; so we can give an error
102 * if there are 4.
103 */
104 num[0][0] = num[1][0] = num[2][0] = num[3][0] = '\0';
105
106 s = (const guchar *) str;
107 pt->num_ints = 0;
108 while (*s && pt->num_ints < 4)
109 {
110
111 i = 0;
112 while (*s && g_ascii_isdigit (*s) && i < NUM_LEN)
113 {
114 num[pt->num_ints][i] = *s;
115 ++s;
116 ++i;
117 }
118
119 if (i > 0)
120 {
121 num[pt->num_ints][i] = '\0';
122 ++(pt->num_ints);
123 }
124
125 if (*s == '\0') break;
126
127 ++s;
128 }
129
130 pt->n[0] = pt->num_ints > 0 ? atoi (num[0]) : 0;
131 pt->n[1] = pt->num_ints > 1 ? atoi (num[1]) : 0;
132 pt->n[2] = pt->num_ints > 2 ? atoi (num[2]) : 0;
133
134 }
135
136
137 /*
138 static void hb_date_determine_dmy(void)
139 {
140 GDate d;
141 gchar buf[128];
142 GDateParseTokens testpt;
143 gint i;
144
145 DB( g_print("\n[dateentry] determine dmy\n") );
146
147 g_date_clear (&d, 1); // clear for scratch use
148
149 // had to pick a random day - don't change this, some strftimes
150 // are broken on some days, and this one is good so far.
151 g_date_set_dmy (&d, 4, 7, 1976);
152 g_date_strftime (buf, 127, "%x", &d);
153
154 hb_date_fill_parse_tokens (buf, &testpt);
155
156 i = 0;
157 while (i < testpt.num_ints)
158 {
159 switch (testpt.n[i])
160 {
161 case 7:
162 dmy_order[i] = G_DATE_MONTH;
163 break;
164 case 4:
165 dmy_order[i] = G_DATE_DAY;
166 break;
167 case 1976:
168 dmy_order[2] = G_DATE_YEAR;
169 break;
170 }
171 ++i;
172 }
173
174 DB( g_print(" dmy legend: 0=day, 1=month, 2=year\n") );
175 DB( g_print(" dmy is: %d %d %d\n", dmy_order[0], dmy_order[1], dmy_order[2]) );
176 }*/
177
178
179 static void hb_date_parse_tokens(GtkWidget *gtkentry, gpointer user_data)
180 {
181 GtkDateEntry *dateentry = user_data;
182 GtkDateEntryPrivate *priv = dateentry->priv;
183 const gchar *str;
184 GDateParseTokens pt;
185
186 str = gtk_entry_get_text (GTK_ENTRY (priv->entry));
187
188 hb_date_fill_parse_tokens(str, &pt);
189 DB( g_print(" -> parsetoken return is %d values :%d %d %d\n", pt.num_ints, pt.n[0], pt.n[1], pt.n[2]) );
190
191 // initialize with today's date
192 g_date_set_time_t(priv->date, time(NULL));
193
194 switch( pt.num_ints )
195 {
196 case 1:
197 DB( g_print(" -> seizured 1 number\n") );
198 if(g_date_valid_day(pt.n[0]))
199 g_date_set_day(priv->date, pt.n[0]);
200 break;
201 case 2:
202 DB( g_print(" -> seizured 2 numbers\n") );
203 if( dmy_order[0] != G_DATE_YEAR )
204 {
205 if( dmy_order[0] == G_DATE_DAY )
206 {
207 if(g_date_valid_day(pt.n[0]))
208 g_date_set_day(priv->date, pt.n[0]);
209 if(g_date_valid_month(pt.n[1]))
210 g_date_set_month(priv->date, pt.n[1]);
211 }
212 else
213 {
214 if(g_date_valid_day(pt.n[1]))
215 g_date_set_day(priv->date, pt.n[1]);
216 if(g_date_valid_month(pt.n[0]))
217 g_date_set_month(priv->date, pt.n[0]);
218 }
219 }
220 break;
221 }
222
223
224
225 }
226
227
228
229
230
231 //end
232
233
234 G_DEFINE_TYPE(GtkDateEntry, gtk_date_entry, GTK_TYPE_BOX)
235
236
237
238 static void
239 gtk_date_entry_class_init (GtkDateEntryClass *class)
240 {
241 GObjectClass *object_class;
242 GtkWidgetClass *widget_class;
243
244 object_class = G_OBJECT_CLASS (class);
245 widget_class = GTK_WIDGET_CLASS (class);
246
247 DB( g_print("\n[dateentry] class_init\n") );
248
249 //object_class->constructor = gtk_date_entry_constructor;
250 //object_class->set_property = gtk_date_entry_set_property;
251 //object_class->get_property = gtk_date_entry_get_property;
252 object_class->dispose = gtk_date_entry_dispose;
253 object_class->finalize = gtk_date_entry_finalize;
254
255 widget_class->destroy = gtk_date_entry_destroy;
256
257 dateentry_signals[CHANGED] =
258 g_signal_new ("changed",
259 G_TYPE_FROM_CLASS (class),
260 G_SIGNAL_RUN_LAST,
261 G_STRUCT_OFFSET (GtkDateEntryClass, changed),
262 NULL, NULL,
263 g_cclosure_marshal_VOID__VOID,
264 G_TYPE_NONE, 0);
265
266 g_type_class_add_private (object_class, sizeof (GtkDateEntryPrivate));
267
268 }
269
270
271 static gboolean
272 gtk_date_entry_entry_focus_out(GtkWidget *widget, GdkEventFocus *event, gpointer user_data)
273 {
274 GtkDateEntry *dateentry = user_data;
275
276 DB( g_print("\n[dateentry] entry focus-out-event %d\n", gtk_widget_is_focus(GTK_WIDGET(dateentry))) );
277
278 gtk_date_entry_entry_activate(GTK_WIDGET(dateentry), dateentry);
279
280 return FALSE;
281 }
282
283 static void
284 gtk_date_entry_init (GtkDateEntry *dateentry)
285 {
286 GtkDateEntryPrivate *priv;
287
288 DB( g_print("\n[dateentry] init\n") );
289
290 /* yes, also priv, need to keep the code readable */
291 dateentry->priv = G_TYPE_INSTANCE_GET_PRIVATE (dateentry,
292 GTK_TYPE_DATE_ENTRY,
293 GtkDateEntryPrivate);
294 priv = dateentry->priv;
295
296
297 /* initialize datas */
298 priv->date = g_date_new();
299 priv->device = NULL;
300 priv->popup_in_progress = FALSE;
301 priv->has_grab = FALSE;
302
303 g_date_set_time_t(priv->date, time(NULL));
304
305 g_date_set_dmy(&priv->mindate, 1, 1, 1900);
306 g_date_set_dmy(&priv->maxdate, 31, 12, 2200);
307
308
309 gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET(dateentry)), GTK_STYLE_CLASS_LINKED);
310
311 //widget=GTK_WIDGET(dateentry);
312
313 priv->entry = gtk_entry_new ();
314
315 //gtk_entry_set_width_chars(GTK_ENTRY(priv->entry), 10);
316 //gtk_entry_set_max_width_chars(GTK_ENTRY(priv->entry), 4);
317
318
319 gtk_box_pack_start (GTK_BOX (dateentry), priv->entry, TRUE, TRUE, 0);
320
321 g_signal_connect (priv->entry, "key-press-event",
322 G_CALLBACK (gtk_date_entry_entry_key_pressed), dateentry);
323
324 g_signal_connect_after (priv->entry, "focus-out-event",
325 G_CALLBACK (gtk_date_entry_entry_focus_out), dateentry);
326
327 g_signal_connect (priv->entry, "activate",
328 G_CALLBACK (gtk_date_entry_entry_activate), dateentry);
329
330
331 priv->button = gtk_button_new ();
332 priv->arrow = gtk_image_new_from_icon_name ("pan-down-symbolic", GTK_ICON_SIZE_BUTTON);
333 gtk_container_add (GTK_CONTAINER (priv->button), priv->arrow);
334 gtk_box_pack_end (GTK_BOX (dateentry), priv->button, FALSE, FALSE, 0);
335 gtk_widget_show_all (priv->button);
336
337 g_signal_connect (priv->button, "clicked",
338 G_CALLBACK (gtk_date_entry_button_clicked), dateentry);
339
340
341 priv->popup_window = gtk_window_new (GTK_WINDOW_POPUP);
342 gtk_window_set_type_hint (
343 GTK_WINDOW (priv->popup_window), GDK_WINDOW_TYPE_HINT_COMBO);
344 gtk_widget_set_events (priv->popup_window,
345 gtk_widget_get_events(priv->popup_window) | GDK_KEY_PRESS_MASK);
346
347 priv->frame = gtk_frame_new (NULL);
348 gtk_container_add (GTK_CONTAINER (priv->popup_window), priv->frame);
349 gtk_frame_set_shadow_type (GTK_FRAME (priv->frame), GTK_SHADOW_ETCHED_IN);
350 gtk_widget_show (priv->frame);
351
352 g_signal_connect (priv->popup_window, "key-press-event",
353 G_CALLBACK (gtk_date_entry_popup_key_event), dateentry);
354
355 g_signal_connect (priv->popup_window, "button-press-event",
356 G_CALLBACK (gtk_date_entry_popup_button_press), dateentry);
357
358
359 priv->calendar = gtk_calendar_new ();
360 gtk_container_add (GTK_CONTAINER (priv->frame), priv->calendar);
361 gtk_widget_show (priv->calendar);
362
363 g_signal_connect (priv->calendar, "prev-year",
364 G_CALLBACK (gtk_date_entry_calendar_year), dateentry);
365 g_signal_connect (priv->calendar, "next-year",
366 G_CALLBACK (gtk_date_entry_calendar_year), dateentry);
367 g_signal_connect (priv->calendar, "prev-month",
368 G_CALLBACK (gtk_date_entry_calendar_year), dateentry);
369 g_signal_connect (priv->calendar, "next-month",
370 G_CALLBACK (gtk_date_entry_calendar_year), dateentry);
371
372 g_signal_connect (priv->calendar, "day-selected",
373 G_CALLBACK (gtk_date_entry_calendar_getfrom), dateentry);
374
375 g_signal_connect (priv->calendar, "day-selected-double-click",
376 G_CALLBACK (gtk_date_entry_calendar_select), dateentry);
377
378 }
379
380
381 GtkWidget *
382 gtk_date_entry_new ()
383 {
384 GtkDateEntry *dateentry;
385
386 DB( g_print("\n[dateentry] new\n") );
387
388 dateentry = g_object_new (GTK_TYPE_DATE_ENTRY, NULL);
389
390 return GTK_WIDGET(dateentry);
391 }
392
393
394 static void
395 gtk_date_entry_destroy (GtkWidget *object)
396 {
397 GtkDateEntry *dateentry = GTK_DATE_ENTRY (object);
398 GtkDateEntryPrivate *priv = dateentry->priv;
399
400 g_return_if_fail(object != NULL);
401 g_return_if_fail(GTK_IS_DATE_ENTRY(object));
402
403 DB( g_print(" \n[dateentry] destroy\n") );
404
405 DB( g_print(" free gtkentry: %p\n", priv->entry) );
406 DB( g_print(" free arrow: %p\n", priv->button) );
407 DB( g_print(" free popup_window: %p\n", priv->popup_window) );
408
409 DB( g_print(" free dateentry: %p\n", dateentry) );
410
411 if(priv->popup_window)
412 gtk_widget_destroy (priv->popup_window);
413 priv->popup_window = NULL;
414
415 if(priv->date)
416 g_date_free(priv->date);
417 priv->date = NULL;
418
419 GTK_WIDGET_CLASS (gtk_date_entry_parent_class)->destroy (object);
420 }
421
422
423
424 static void
425 gtk_date_entry_dispose (GObject *gobject)
426 {
427 //GtkDateEntry *self = GTK_DATE_ENTRY (gobject);
428
429 DB( g_print(" \n[dateentry] dispose\n") );
430
431
432 //g_clear_object (&self->priv->an_object);
433
434 G_OBJECT_CLASS (gtk_date_entry_parent_class)->dispose (gobject);
435 }
436
437
438
439
440 static void
441 gtk_date_entry_finalize (GObject *gobject)
442 {
443 //GtkDateEntry *self = GTK_DATE_ENTRY (gobject);
444
445 DB( g_print(" \n[dateentry] finalize\n") );
446
447
448 //g_date_free(self->date);
449 //g_free (self->priv->a_string);
450
451 /* Always chain up to the parent class; as with dispose(), finalize()
452 * is guaranteed to exist on the parent's class virtual function table
453 */
454 G_OBJECT_CLASS(gtk_date_entry_parent_class)->finalize (gobject);
455 }
456
457
458 /*
459 **
460 */
461 void gtk_date_entry_set_date(GtkDateEntry *dateentry, guint32 julian_days)
462 {
463 GtkDateEntryPrivate *priv = dateentry->priv;
464
465 DB( g_print(" \n[dateentry] set date\n") );
466
467 g_return_if_fail (GTK_IS_DATE_ENTRY (dateentry));
468
469 if(g_date_valid_julian(julian_days))
470 {
471 g_date_set_julian (priv->date, julian_days);
472 }
473 else
474 {
475 g_date_set_time_t(priv->date, time(NULL));
476 }
477 gtk_date_entry_entry_set_text(dateentry);
478 }
479
480 /*
481 **
482 */
483 void gtk_date_entry_set_mindate(GtkDateEntry *dateentry, guint32 julian_days)
484 {
485 GtkDateEntryPrivate *priv = dateentry->priv;
486
487 DB( g_print(" \n[dateentry] set mindate\n") );
488
489 g_return_if_fail (GTK_IS_DATE_ENTRY (dateentry));
490
491 if(g_date_valid_julian(julian_days))
492 {
493 g_date_set_julian (&priv->mindate, julian_days);
494 }
495 }
496
497
498 /*
499 **
500 */
501 void gtk_date_entry_set_maxdate(GtkDateEntry *dateentry, guint32 julian_days)
502 {
503 GtkDateEntryPrivate *priv = dateentry->priv;
504
505 DB( g_print(" \n[dateentry] set maxdate\n") );
506
507 g_return_if_fail (GTK_IS_DATE_ENTRY (dateentry));
508
509 if(g_date_valid_julian(julian_days))
510 {
511 g_date_set_julian (&priv->maxdate, julian_days);
512 }
513 }
514
515
516 guint32 gtk_date_entry_get_date(GtkDateEntry * dateentry)
517 {
518 GtkDateEntryPrivate *priv = dateentry->priv;
519
520 DB( g_print(" \n[dateentry] get date\n") );
521
522 g_return_val_if_fail (GTK_IS_DATE_ENTRY (dateentry), 0);
523
524 return(g_date_get_julian(priv->date));
525 }
526
527
528 static void
529 gtk_date_entry_entry_set_text(GtkDateEntry * dateentry)
530 {
531 GtkDateEntryPrivate *priv = dateentry->priv;
532 gchar buffer[256];
533
534 DB( g_print("\n[dateentry] entry set text\n") );
535
536 g_date_clamp(priv->date, &priv->mindate, &priv->maxdate);
537
538
539 if(g_date_valid(priv->date) == TRUE)
540 {
541 g_date_strftime (buffer, 256 - 1, "%x", priv->date);
542 gtk_entry_set_text (GTK_ENTRY (priv->entry), buffer);
543
544 DB( g_print(" = %s\n", buffer) );
545 }
546 else
547 gtk_entry_set_text (GTK_ENTRY (priv->entry), "??");
548
549
550 /* emit the signal */
551 if(priv->lastdate != g_date_get_julian(priv->date))
552 {
553 DB( g_print(" **emit 'changed' signal**\n") );
554
555 g_signal_emit_by_name (dateentry, "changed", NULL, NULL);
556 }
557
558 priv->lastdate = g_date_get_julian(priv->date);
559
560 }
561
562
563 static void
564 gtk_date_entry_entry_activate(GtkWidget *gtkentry, gpointer user_data)
565 {
566 GtkDateEntry *dateentry = user_data;
567 GtkDateEntryPrivate *priv = dateentry->priv;
568 const gchar *str;
569
570 DB( g_print("\n[dateentry] entry_activate\n") );
571
572 str = gtk_entry_get_text (GTK_ENTRY (priv->entry));
573
574 //1) we parse the string according to the locale
575 g_date_set_parse (priv->date, str);
576 if(g_date_valid(priv->date) == FALSE)
577 {
578 //2) give a try to tokens: day, day/month, month/day
579 hb_date_parse_tokens(gtkentry, user_data);
580 }
581
582 //3) at last if date still invalid, put today's dateentry_signals
583 // we should consider just warn the user here
584 if(g_date_valid(priv->date) == FALSE)
585 {
586 /* today's date */
587 g_date_set_time_t(priv->date, time(NULL));
588 }
589
590 gtk_date_entry_entry_set_text(dateentry);
591
592 }
593
594
595 static void
596 gtk_date_entry_calendar_year(GtkWidget *calendar, GtkDateEntry *dateentry)
597 {
598 GtkDateEntryPrivate *priv = dateentry->priv;
599 guint year, month, day;
600
601 DB( g_print(" (dateentry) year changed\n") );
602
603 gtk_calendar_get_date (GTK_CALENDAR (priv->calendar), &year, &month, &day);
604 if( year < 1900)
605 g_object_set(calendar, "year", 1900, NULL);
606
607 if( year > 2200)
608 g_object_set(calendar, "year", 2200, NULL);
609
610 }
611
612
613 static void
614 gtk_date_entry_calendar_getfrom(GtkWidget * calendar, GtkDateEntry * dateentry)
615 {
616 GtkDateEntryPrivate *priv = dateentry->priv;
617 guint year, month, day;
618
619 DB( g_print(" (dateentry) calendar_getfrom\n") );
620
621 gtk_calendar_get_date (GTK_CALENDAR (priv->calendar), &year, &month, &day);
622 g_date_set_dmy (priv->date, day, month + 1, year);
623 gtk_date_entry_entry_set_text(dateentry);
624 }
625
626
627 static gint
628 gtk_date_entry_calendar_select(GtkWidget * calendar, gpointer user_data)
629 {
630 GtkDateEntry *dateentry = user_data;
631
632 DB( g_print(" (dateentry) calendar_select\n") );
633
634 gtk_date_entry_calendar_getfrom(NULL, dateentry);
635
636 gtk_date_entry_popdown(dateentry);
637 return FALSE;
638 }
639
640
641 static gint
642 gtk_date_entry_entry_key_pressed (GtkWidget *widget, GdkEventKey *event, gpointer user_data)
643 {
644 GtkDateEntry *dateentry = user_data;
645 GtkDateEntryPrivate *priv = dateentry->priv;
646
647 DB( g_print("\n[dateentry] entry key pressed: state=%04x, keyval=%04x\n", event->state, event->keyval) );
648
649 if( event->keyval == GDK_KEY_Up )
650 {
651 if( !(event->state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK)) )
652 {
653 g_date_add_days (priv->date, 1);
654 gtk_date_entry_entry_set_text(dateentry);
655 }
656 else
657 if( event->state & GDK_SHIFT_MASK )
658 {
659 g_date_add_months (priv->date, 1);
660 gtk_date_entry_entry_set_text(dateentry);
661 }
662 else
663 if( event->state & GDK_CONTROL_MASK )
664 {
665 g_date_add_years (priv->date, 1);
666 gtk_date_entry_entry_set_text(dateentry);
667 }
668 return TRUE;
669 }
670 else
671 if( event->keyval == GDK_KEY_Down )
672 {
673 if( !(event->state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK)) )
674 {
675 g_date_subtract_days (priv->date, 1);
676 gtk_date_entry_entry_set_text(dateentry);
677 }
678 else
679 if( event->state & GDK_SHIFT_MASK )
680 {
681 g_date_subtract_months (priv->date, 1);
682 gtk_date_entry_entry_set_text(dateentry);
683 }
684 else
685 if( event->state & GDK_CONTROL_MASK )
686 {
687 g_date_subtract_years (priv->date, 1);
688 gtk_date_entry_entry_set_text(dateentry);
689 }
690 return TRUE;
691 }
692
693 return FALSE;
694 }
695
696
697 static void
698 gtk_date_entry_popup_position (GtkDateEntry * dateentry)
699 {
700 GtkDateEntryPrivate *priv = dateentry->priv;
701 gint x, y;
702 gint bwidth, bheight;
703 GtkRequisition req;
704 GdkWindow *gdkwindow;
705 GtkAllocation allocation;
706
707 DB( g_print("\n[dateentry] position popup\n") );
708
709 gtk_widget_get_preferred_size (priv->popup_window, NULL, &req);
710
711 gdkwindow = gtk_widget_get_window(priv->button);
712 gdk_window_get_origin (gdkwindow, &x, &y);
713
714 gtk_widget_get_allocation(priv->button, &allocation);
715 x += allocation.x;
716 y += allocation.y;
717 bwidth = allocation.width;
718 bheight = allocation.height;
719
720 x += bwidth - req.width;
721 y += bheight;
722
723 if (x < 0)
724 x = 0;
725
726 if (y < 0)
727 y = 0;
728
729 gtk_window_move (GTK_WINDOW (priv->popup_window), x, y);
730 }
731
732
733 static void
734 gtk_date_entry_button_clicked (GtkWidget * widget, GtkDateEntry * dateentry)
735 {
736 GdkEvent *event;
737
738 DB( g_print("\n[dateentry] button_clicked\n") );
739
740 /* Obtain the GdkEvent that triggered
741 * the date button's "clicked" signal. */
742 event = gtk_get_current_event ();
743
744 gtk_date_entry_popup(dateentry, event);
745
746 }
747
748
749 static void
750 gtk_date_entry_popup(GtkDateEntry * dateentry, GdkEvent *event)
751 {
752 GtkDateEntryPrivate *priv = dateentry->priv;
753 const char *str;
754 int month;
755 GdkDevice *event_device;
756 GdkDevice *assoc_device;
757 GdkDevice *keyboard_device;
758 GdkDevice *pointer_device;
759 GdkWindow *window;
760 GdkGrabStatus grab_status;
761 guint event_time;
762
763
764 DB( g_print("\n[dateentry] popup_display\n****\n\n") );
765
766 /* update */
767 str = gtk_entry_get_text (GTK_ENTRY (priv->entry));
768 g_date_set_parse (priv->date, str);
769
770 if(g_date_valid(priv->date) == TRUE)
771 {
772 /* GtkCalendar expects month to be in 0-11 range (inclusive) */
773 month = g_date_get_month (priv->date) - 1;
774 gtk_calendar_select_month (GTK_CALENDAR (priv->calendar),
775 CLAMP (month, 0, 11),
776 g_date_get_year (priv->date));
777 gtk_calendar_select_day (GTK_CALENDAR (priv->calendar),
778 g_date_get_day (priv->date));
779 }
780
781
782 /* popup */
783 gtk_date_entry_popup_position(dateentry);
784 gtk_widget_show (priv->popup_window);
785 gtk_widget_grab_focus (priv->popup_window);
786 gtk_grab_add (priv->popup_window);
787
788 window = gtk_widget_get_window (priv->popup_window);
789
790 g_return_if_fail (priv->grab_keyboard == NULL);
791 g_return_if_fail (priv->grab_pointer == NULL);
792
793 event_device = gdk_event_get_device (event);
794 assoc_device = gdk_device_get_associated_device (event_device);
795
796 event_time = gdk_event_get_time (event);
797
798 if (gdk_device_get_source (event_device) == GDK_SOURCE_KEYBOARD) {
799 keyboard_device = event_device;
800 pointer_device = assoc_device;
801 } else {
802 keyboard_device = assoc_device;
803 pointer_device = event_device;
804 }
805
806 if (keyboard_device != NULL) {
807 grab_status = gdk_device_grab (
808 keyboard_device,
809 window,
810 GDK_OWNERSHIP_WINDOW,
811 TRUE,
812 GDK_KEY_PRESS_MASK |
813 GDK_KEY_RELEASE_MASK,
814 NULL,
815 event_time);
816 if (grab_status == GDK_GRAB_SUCCESS) {
817 priv->grab_keyboard =
818 g_object_ref (keyboard_device);
819 }
820 }
821
822 if (pointer_device != NULL) {
823 grab_status = gdk_device_grab (
824 pointer_device,
825 window,
826 GDK_OWNERSHIP_WINDOW,
827 TRUE,
828 GDK_BUTTON_PRESS_MASK |
829 GDK_BUTTON_RELEASE_MASK |
830 GDK_POINTER_MOTION_MASK,
831 NULL,
832 event_time);
833 if (grab_status == GDK_GRAB_SUCCESS) {
834 priv->grab_pointer =
835 g_object_ref (pointer_device);
836 } else if (priv->grab_keyboard != NULL) {
837 gdk_device_ungrab (
838 priv->grab_keyboard,
839 event_time);
840 g_object_unref (priv->grab_keyboard);
841 priv->grab_keyboard = NULL;
842 }
843 }
844
845 gdk_window_focus (window, event_time);
846
847 }
848
849
850 static void
851 gtk_date_entry_popdown(GtkDateEntry *dateentry)
852 {
853 GtkDateEntryPrivate *priv = dateentry->priv;
854
855 DB( g_print("\n[dateentry] popdown\n") );
856
857 gtk_widget_hide (priv->popup_window);
858 gtk_grab_remove (priv->popup_window);
859
860 if (priv->grab_keyboard != NULL) {
861 gdk_device_ungrab (
862 priv->grab_keyboard,
863 GDK_CURRENT_TIME);
864 g_object_unref (priv->grab_keyboard);
865 priv->grab_keyboard = NULL;
866 }
867
868 if (priv->grab_pointer != NULL) {
869 gdk_device_ungrab (
870 priv->grab_pointer,
871 GDK_CURRENT_TIME);
872 g_object_unref (priv->grab_pointer);
873 priv->grab_pointer = NULL;
874 }
875
876 }
877
878
879
880
881
882 static gint
883 gtk_date_entry_popup_key_event (GtkWidget *widget, GdkEventKey *event, gpointer user_data)
884 {
885 GtkDateEntry *dateentry = user_data;
886
887 DB( g_print("\n[dateentry] popup_key_event%d\n", event->keyval) );
888
889 DB( g_print(" -> key=%d\n", event->keyval) );
890
891 if (event->keyval != GDK_KEY_Escape && event->keyval != GDK_KEY_Return)
892 return FALSE;
893
894 g_signal_stop_emission_by_name (widget, "key-press-event");
895
896 gtk_date_entry_popdown(dateentry);
897
898 return TRUE;
899 }
900
901
902 static gint
903 gtk_date_entry_popup_button_press (GtkWidget * widget, GdkEvent * event, gpointer user_data)
904 {
905 GtkDateEntry *dateentry = user_data;
906 //GtkDateEntryPrivate *priv = dateentry->priv;
907 GtkWidget *child;
908
909 DB( g_print("\n[dateentry] popup_button_press\n") );
910
911 child = gtk_get_event_widget (event);
912
913 /* We don't ask for button press events on the grab widget, so
914 * if an event is reported directly to the grab widget, it must
915 * be on a window outside the application (and thus we remove
916 * the popup window). Otherwise, we check if the widget is a child
917 * of the grab widget, and only remove the popup window if it
918 * is not.
919 */
920 if (child != widget) {
921 while (child) {
922 if (child == widget)
923 return FALSE;
924 child = gtk_widget_get_parent (child);
925 }
926 }
927
928 gtk_date_entry_popdown(dateentry);
929
930 return TRUE;
931 }
932
This page took 0.07245 seconds and 4 git commands to generate.