source: trunk/third/gnome-core/panel/basep-widget.c @ 17167

Revision 17167, 56.1 KB checked in by ghudson, 23 years ago (diff)
Merge with gnome-core 1.4.0.6.
Line 
1/* Gnome panel: basep widget
2 * (C) 1997 the Free Software Foundation
3 *
4 * Authors:  George Lebl
5 *           Jacob Berkman
6 */
7#include <math.h>
8#include <config.h>
9#include <X11/Xlib.h>
10#include <gtk/gtk.h>
11#include <gdk/gdkx.h>
12#include <gnome.h>
13#include "panel-widget.h"
14#include "basep-widget.h"
15#include "panel-util.h"
16#include "panel_config_global.h"
17#include "foobar-widget.h"
18#include "drawer-widget.h"
19#include "border-widget.h"
20#include "edge-widget.h"
21#include "aligned-widget.h"
22#include "xstuff.h"
23#include "multiscreen-stuff.h"
24
25extern gboolean panel_applet_in_drag;
26extern GSList *panel_list;
27
28extern int applets_to_sync;
29extern int panels_to_sync;
30extern int need_complete_save;
31
32/*global settings*/
33extern int pw_explicit_step;
34extern int pw_drawer_step;
35extern int pw_auto_step;
36extern int pw_minimized_size;
37extern int pw_minimize_delay;
38extern int pw_maximize_delay;
39extern gboolean pw_disable_animations;
40extern PanelMovementType pw_movement_type;
41
42extern GtkTooltips *panel_tooltips;
43
44extern GlobalConfig global_config;
45
46static void basep_widget_class_init     (BasePWidgetClass *klass);
47static void basep_widget_init           (BasePWidget      *basep);
48
49static void basep_pos_class_init (BasePPosClass *klass);
50static void basep_pos_init (BasePPos *pos);
51static gboolean basep_leave_notify (GtkWidget *widget, GdkEventCrossing *event);
52static gboolean basep_enter_notify (GtkWidget *widget, GdkEventCrossing *event);
53static void basep_style_set (GtkWidget *widget, GtkStyle *previous_style);
54
55static void basep_widget_destroy (GtkObject *o);
56
57static GtkWindowClass *basep_widget_parent_class = NULL;
58static GtkObjectClass *basep_pos_parent_class = NULL;
59
60/************************
61 widget core
62 ************************/
63
64GtkType
65basep_widget_get_type (void)
66{
67        static GtkType basep_widget_type = 0;
68
69        if (!basep_widget_type) {
70                GtkTypeInfo basep_widget_info = {
71                        "BasePWidget",
72                        sizeof (BasePWidget),
73                        sizeof (BasePWidgetClass),
74                        (GtkClassInitFunc) basep_widget_class_init,
75                        (GtkObjectInitFunc) basep_widget_init,
76                        NULL,
77                        NULL,
78                        NULL
79                };
80
81                basep_widget_type = gtk_type_unique (gtk_window_get_type (),
82                                                     &basep_widget_info);
83        }
84
85        return basep_widget_type;
86}
87
88enum {
89        /*TYPE_CHANGE_SIGNAL,*/
90        MODE_CHANGE_SIGNAL,
91        STATE_CHANGE_SIGNAL,
92        SCREEN_CHANGE_SIGNAL,
93        WIDGET_LAST_SIGNAL
94};
95
96static guint basep_widget_signals[WIDGET_LAST_SIGNAL] = { 0 };
97
98static BasePPosClass *
99basep_widget_get_pos_class (BasePWidget *basep) {
100        BasePPosClass *klass;
101
102        g_return_val_if_fail (IS_BASEP_WIDGET(basep), NULL);
103        g_return_val_if_fail (IS_BASEP_POS(basep->pos), NULL);
104
105        klass = BASEP_POS_CLASS(GTK_OBJECT(basep->pos)->klass);
106
107        g_return_val_if_fail (IS_BASEP_POS_CLASS (klass), NULL);
108
109        return klass;
110}
111
112static void
113basep_widget_realize (GtkWidget *w)
114{
115        BasePWidget *basep = BASEP_WIDGET (w);
116        BasePPosClass *klass;
117
118        g_return_if_fail (IS_BASEP_WIDGET (basep));
119
120        gtk_window_set_wmclass (GTK_WINDOW (basep),
121                                "panel_window", "Panel");
122
123        GTK_WIDGET_CLASS (basep_widget_parent_class)->realize (w);
124
125        basep_widget_update_winhints (basep);
126        xstuff_set_no_group_and_no_input (w->window);
127
128        set_frame_colors (PANEL_WIDGET (basep->panel),
129                          basep->frame,
130                          basep->hidebutton_n,
131                          basep->hidebutton_e,
132                          basep->hidebutton_w,
133                          basep->hidebutton_s);
134
135       
136        klass = basep_widget_get_pos_class (basep);
137        g_return_if_fail (klass);
138        if (klass->realize != NULL)
139                klass->realize (w);
140}
141
142static void
143basep_widget_map (GtkWidget *w)
144{
145        BasePWidget *basep = BASEP_WIDGET (w);
146
147        g_return_if_fail (IS_BASEP_WIDGET (basep));
148
149        if (GTK_WIDGET_CLASS (basep_widget_parent_class)->map != NULL)
150                GTK_WIDGET_CLASS (basep_widget_parent_class)->map (w);
151
152        basep_widget_update_winhints (basep);
153}
154
155static void
156basep_widget_size_request (GtkWidget *widget,
157                           GtkRequisition *requisition)
158{
159        GtkRequisition chreq;
160
161        BasePWidget *basep = BASEP_WIDGET(widget);
162        BasePPosClass *klass = basep_widget_get_pos_class (basep);
163
164        g_assert (klass);
165
166        if (basep->request_cube) {
167                requisition->width = requisition->height =
168                        PANEL_MINIMUM_WIDTH;
169                basep->request_cube = FALSE;
170                return;
171        }
172
173        gtk_widget_size_request (basep->ebox, &chreq);
174
175        /* this typically only does stuff on edge panels */
176        if (klass->get_size) {
177                int w,h;
178                w = chreq.width;
179                h = chreq.height;
180                klass->get_size(basep, &w, &h);
181                chreq.width = w;
182                chreq.height = h;
183        }
184
185        if (basep->state != BASEP_SHOWN) {
186                int w,h;
187                PanelOrientType hide_orient =
188                        klass->get_hide_orient (basep);
189                w = chreq.width;
190                h = chreq.height;
191                klass->get_hide_size (basep, hide_orient, &w, &h);
192                chreq.width = w;
193                chreq.height = h;
194        }
195
196        requisition->width = chreq.width;
197        requisition->height = chreq.height;
198}
199
200static void
201basep_widget_size_allocate (GtkWidget *widget,
202                            GtkAllocation *allocation)
203{
204        GtkAllocation challoc;
205        GtkRequisition chreq;
206       
207        BasePWidget *basep = BASEP_WIDGET(widget);
208        BasePPosClass *klass = basep_widget_get_pos_class (basep);
209       
210        /*we actually want to ignore the size_reqeusts since they
211          are sometimes a cube for the flicker prevention*/
212#ifdef PANEL_DEBUG
213        if (basep->state == BASEP_MOVING)
214                g_warning ("size_allocate whilst moving");
215#endif
216
217        gtk_widget_size_request (basep->ebox, &chreq);
218
219        if (klass->get_size) {
220                int w,h;
221                w = chreq.width;
222                h = chreq.height;
223                klass->get_size(basep, &w, &h);
224                chreq.width = w;
225                chreq.height = h;
226        }
227        if (klass->get_pos) {
228                int x,y;
229                klass->get_pos (basep, &x, &y,
230                                chreq.width,
231                                chreq.height);
232                allocation->x = x;
233                allocation->y = y;
234        }
235
236        allocation->width = challoc.width = chreq.width;
237        allocation->height = challoc.height = chreq.height;
238        challoc.x = challoc.y = 0;
239
240        basep->shown_alloc = *allocation;
241
242        if (basep->state != BASEP_SHOWN) {
243                int w,h,x,y;
244                PanelOrientType hide_orient =
245                        klass->get_hide_orient (basep);
246
247                w = allocation->width;
248                h = allocation->height;
249                klass->get_hide_size (basep, hide_orient, &w,&h);
250                allocation->width = w;
251                allocation->height = h;
252
253                x = allocation->x;
254                y = allocation->y;
255                klass->get_hide_pos (basep, hide_orient,
256                                     &x, &y,
257                                     basep->shown_alloc.width,
258                                     basep->shown_alloc.height);
259                allocation->x = x;
260                allocation->y = y;
261
262                basep_widget_get_position (basep, hide_orient,
263                                           &x, &y,
264                                           allocation->width,
265                                           allocation->height);
266                challoc.x = x;
267                challoc.y = y;
268        }
269
270        if (basep->keep_in_screen) {
271                gint16 max;
272
273                max = multiscreen_width (basep->screen) -
274                        allocation->width +
275                        multiscreen_x (basep->screen);
276
277                if (allocation->x < multiscreen_x (basep->screen))
278                        allocation->x = multiscreen_x (basep->screen);
279                else if (allocation->x > max)
280                        allocation->x = max;
281
282
283                max = multiscreen_height (basep->screen) -
284                        allocation->height +
285                        multiscreen_y (basep->screen);
286
287                if (allocation->y < multiscreen_y (basep->screen))
288                        allocation->y = multiscreen_y (basep->screen);
289                else if (allocation->y > max)
290                        allocation->y = max;
291                                       
292        }
293        widget->allocation = *allocation;
294
295        if (GTK_WIDGET_REALIZED(widget)) {
296                xstuff_set_pos_size (widget->window,
297                                     allocation->x,
298                                     allocation->y,
299                                     allocation->width,
300                                     allocation->height);
301        }
302
303        gtk_widget_size_allocate (basep->ebox, &challoc);
304}
305
306static void
307basep_widget_mode_change (BasePWidget *basep, BasePMode mode)
308{
309        if (IS_BORDER_WIDGET (basep))
310                basep_border_queue_recalc (basep->screen);
311}
312
313static void
314basep_widget_state_change (BasePWidget *basep, BasePState state)
315{
316        if (IS_BORDER_WIDGET (basep))
317                basep_border_queue_recalc (basep->screen);
318}
319
320static void
321basep_widget_real_screen_change (BasePWidget *basep, int screen)
322{
323        if (basep->screen != screen) {
324                basep_border_queue_recalc (basep->screen);
325                basep->screen = screen;
326                /* this will queue border recalc in the new screen */
327                gtk_widget_queue_resize (GTK_WIDGET (basep));
328                panels_to_sync = TRUE;
329
330                update_config_screen (basep);
331        }
332}
333
334static void
335basep_widget_class_init (BasePWidgetClass *klass)
336{
337        GtkObjectClass *object_class = GTK_OBJECT_CLASS (klass);
338        GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
339
340        basep_widget_parent_class = gtk_type_class (gtk_window_get_type ());
341
342        /*basep_widget_signals[TYPE_CHANGE_SIGNAL] =
343                gtk_signal_new("type_change",
344                               GTK_RUN_LAST,
345                               object_class->type,
346                               GTK_SIGNAL_OFFSET(BasePWidgetClass,
347                                                 type_change),
348                               gtk_marshal_NONE__ENUM,
349                               GTK_TYPE_NONE,
350                               1, GTK_TYPE_ENUM);*/
351
352        basep_widget_signals[MODE_CHANGE_SIGNAL] =
353                gtk_signal_new("mode_change",
354                               GTK_RUN_LAST,
355                               object_class->type,
356                               GTK_SIGNAL_OFFSET(BasePWidgetClass,
357                                                 mode_change),
358                               gtk_marshal_NONE__ENUM,
359                               GTK_TYPE_NONE,
360                               1, GTK_TYPE_ENUM);
361
362        basep_widget_signals[STATE_CHANGE_SIGNAL] =
363                gtk_signal_new("state_change",
364                               GTK_RUN_LAST,
365                               object_class->type,
366                               GTK_SIGNAL_OFFSET(BasePWidgetClass,
367                                                 state_change),
368                               gtk_marshal_NONE__ENUM,
369                               GTK_TYPE_NONE,
370                               1, GTK_TYPE_ENUM);
371
372        basep_widget_signals[SCREEN_CHANGE_SIGNAL] =
373                gtk_signal_new("screen_change",
374                               GTK_RUN_LAST,
375                               object_class->type,
376                               GTK_SIGNAL_OFFSET(BasePWidgetClass,
377                                                 screen_change),
378                               gtk_marshal_NONE__INT,
379                               GTK_TYPE_NONE,
380                               1,
381                               GTK_TYPE_INT);
382
383        gtk_object_class_add_signals(object_class,
384                                     basep_widget_signals,
385                                     WIDGET_LAST_SIGNAL);
386
387        klass->mode_change = basep_widget_mode_change;
388        klass->state_change = basep_widget_state_change;
389        klass->screen_change = basep_widget_real_screen_change;
390
391        widget_class->size_request = basep_widget_size_request;
392        widget_class->size_allocate = basep_widget_size_allocate;
393        widget_class->realize = basep_widget_realize;
394        widget_class->map = basep_widget_map;
395        widget_class->enter_notify_event = basep_enter_notify;
396        widget_class->leave_notify_event = basep_leave_notify;
397        widget_class->style_set = basep_style_set;
398
399        object_class->destroy = basep_widget_destroy;
400}
401
402/* pos core */
403GtkType
404basep_pos_get_type (void)
405{
406        static GtkType basep_pos_type = 0;
407       
408        if (!basep_pos_type) {
409                GtkTypeInfo basep_pos_info = {
410                        "BasePPos",
411                        sizeof (BasePPos),
412                        sizeof (BasePPosClass),
413                        (GtkClassInitFunc) basep_pos_class_init,
414                        (GtkObjectInitFunc) basep_pos_init,
415                        (GtkArgSetFunc) NULL,
416                        (GtkArgGetFunc) NULL
417                };
418               
419                basep_pos_type = gtk_type_unique (gtk_object_get_type (),
420                                                  &basep_pos_info);
421        }
422
423        return basep_pos_type;
424}
425
426#if 0
427enum {
428        POS_CHANGE_SIGNAL,
429        POS_LAST_SIGNAL
430}
431static guint basep_pos_signals[POS_LAST_SIGNAL] = { 0 };
432#endif
433
434static void
435basep_pos_get_hide_size (BasePWidget *basep,
436                         PanelOrientType hide_orient,
437                         int *w, int *h)
438{
439        switch (hide_orient) {
440        case ORIENT_UP:
441        case ORIENT_DOWN:
442                *h = (basep->state == BASEP_AUTO_HIDDEN)
443                        ? pw_minimized_size
444                        : get_requisition_height (basep->hidebutton_n);
445                break;
446        case ORIENT_RIGHT:
447        case ORIENT_LEFT:
448                *w = (basep->state == BASEP_AUTO_HIDDEN)
449                        ? pw_minimized_size
450                        : get_requisition_width (basep->hidebutton_e);
451                break;
452        }
453        *w = MAX (*w, 1);
454        *h = MAX (*h, 1);
455}
456
457static void
458basep_pos_get_hide_pos (BasePWidget *basep,
459                        PanelOrientType hide_orient,
460                        int *x, int *y,
461                        int w, int h)
462{
463        switch (hide_orient) {
464        case ORIENT_UP:
465        case ORIENT_LEFT:
466                break;
467        case ORIENT_RIGHT:
468                *x += w - ((basep->state == BASEP_AUTO_HIDDEN)
469                           ? pw_minimized_size
470                           : get_requisition_width (basep->hidebutton_w));
471                break;
472        case ORIENT_DOWN:
473                *y += h - ((basep->state == BASEP_AUTO_HIDDEN)
474                           ? pw_minimized_size
475                           : get_requisition_height (basep->hidebutton_s));
476                break;
477        }
478}
479               
480static void
481basep_pos_class_init (BasePPosClass *klass)
482{
483        /*GtkObjectClass *object_class = GTK_OBJECT_CLASS(klass);*/
484
485        basep_pos_parent_class = gtk_type_class(gtk_object_get_type ());
486
487        klass->get_hide_size = basep_pos_get_hide_size;
488        klass->get_hide_pos = basep_pos_get_hide_pos;
489}       
490
491/* nothing to see here... */
492static void
493basep_pos_init (BasePPos *pos)
494{
495        return;
496}
497
498static gboolean
499basep_leave_notify (GtkWidget *widget,
500                    GdkEventCrossing *event)
501{
502        BasePWidget *basep = BASEP_WIDGET (widget);
503
504#ifdef PANEL_DEBUG
505        if (basep->state == BASEP_MOVING)
506                g_warning ("moving in leave_notify");
507
508        if (basep->leave_notify_timer_tag != 0)
509                g_warning ("timeout already queued");
510#endif
511        if (event->detail == GDK_NOTIFY_INFERIOR)
512                return FALSE;
513       
514        basep_widget_queue_autohide (basep);
515
516        if (GTK_WIDGET_CLASS (basep_widget_parent_class)->leave_notify_event)
517                return GTK_WIDGET_CLASS (basep_widget_parent_class)->leave_notify_event (widget, event);
518        else
519                return FALSE;
520}
521
522static gboolean
523basep_enter_notify (GtkWidget *widget,
524                    GdkEventCrossing *event)
525{
526        BasePWidget *basep = BASEP_WIDGET (widget);
527
528        if (basep->state == BASEP_AUTO_HIDDEN &&
529            event->detail != GDK_NOTIFY_INFERIOR) {
530
531                g_assert (basep->mode == BASEP_AUTO_HIDE);
532#ifdef PANEL_DEBUG
533                g_print ("detail: %d\n", event->detail);
534#endif
535                if (basep->leave_notify_timer_tag != 0) {
536                        gtk_timeout_remove (basep->leave_notify_timer_tag);
537                        basep->leave_notify_timer_tag = 0;
538                }
539
540                basep_widget_queue_autoshow (basep);
541        } 
542
543        if (global_config.autoraise)
544                gdk_window_raise (GTK_WIDGET(basep)->window);
545
546        if (GTK_WIDGET_CLASS (basep_widget_parent_class)->enter_notify_event)
547                return GTK_WIDGET_CLASS (basep_widget_parent_class)->enter_notify_event (widget, event);
548        else
549                return FALSE;
550}
551
552void
553basep_widget_get_position (BasePWidget *basep, PanelOrientType hide_orient,
554                           int *x, int *y, int w, int h)
555{
556        *x = *y = 0;
557        switch(hide_orient) {
558        case ORIENT_UP:
559                if(h < basep->shown_alloc.height)
560                        *y = h - basep->shown_alloc.height;
561                break;
562        case ORIENT_LEFT:
563                if(w < basep->shown_alloc.width)
564                        *x = w - basep->shown_alloc.width;
565                break;
566        default:
567                break;
568        }
569}
570
571static void
572basep_widget_set_ebox_orient(BasePWidget *basep,
573                             PanelOrientType hide_orient)
574{
575        XSetWindowAttributes xattributes;
576
577        switch(hide_orient) {
578        case ORIENT_UP:
579        case ORIENT_LEFT:
580                xattributes.win_gravity = SouthEastGravity;
581                break;
582        case ORIENT_DOWN:
583        case ORIENT_RIGHT:
584        default:
585                xattributes.win_gravity = NorthWestGravity;
586                break;
587        }
588
589        XChangeWindowAttributes (GDK_WINDOW_XDISPLAY(basep->ebox->window),
590                                 GDK_WINDOW_XWINDOW(basep->ebox->window),
591                                 CWWinGravity,  &xattributes);
592       
593}
594
595static int
596move_step(int src, int dest, long start_time, long end_time, long cur_time)
597{
598        double percentage;
599       
600        if(src == dest)
601                return dest;
602
603        if(global_config.simple_movement) {
604                percentage = ((double)(cur_time-start_time))/(end_time-start_time);
605                if(percentage>1.0)
606                        percentage = 1.0;
607                return  src + ((dest - src)*percentage);
608        } else {
609                double n = cur_time-start_time;
610                double d = end_time-start_time;
611
612                if(n<d) {
613                        /*blah blah blah just a simple function to make the
614                          movement more "sin" like ... we run it twice to
615                          pronounce make it more pronounced*/
616                        percentage = sin(M_PI*(n/d)-M_PI/2)/2+0.5;
617                        percentage = sin(M_PI*percentage-M_PI/2)/2+0.5;
618                        if(percentage<0.0)
619                                percentage = 0.0;
620                        else if(percentage>1.0)
621                                percentage = 1.0;
622                } else
623                        percentage = 1.0;
624
625                return  src + ((dest - src)*percentage);
626        }
627}
628
629void
630basep_widget_do_hiding(BasePWidget *basep, PanelOrientType hide_orient,
631                       int leftover, int step)
632{
633        GtkWidget *wid;
634        int ox,oy,ow,oh;
635        int x,y,w,h;
636        int dx,dy,dw,dh;
637        int diff;
638       
639        g_return_if_fail(basep != NULL);
640        g_return_if_fail(IS_BASEP_WIDGET(basep));
641
642        if (basep->state != BASEP_MOVING) {
643#ifdef PANEL_DEBUG
644                g_warning ("do_hiding whilst not moving");
645#endif
646                return;
647        }
648
649        wid = GTK_WIDGET(basep);
650       
651        ox = x = basep->shown_alloc.x;
652        oy = y = basep->shown_alloc.y;
653        ow = w = basep->shown_alloc.width;
654        oh = h = basep->shown_alloc.height;
655       
656        switch(hide_orient) {
657        case ORIENT_UP:
658                diff = h-leftover;
659                dx = x;
660                dy = y;
661                dw = w;
662                dh = leftover;
663                break;
664        case ORIENT_DOWN:
665                diff = h-leftover;
666                dx = x;
667                dy = y+h-leftover;
668                dw = w;
669                dh = leftover;
670                break;
671        case ORIENT_LEFT:
672                diff = w-leftover;
673                dx = x;
674                dy = y;
675                dw = leftover;
676                dh = h;
677                break;
678        case ORIENT_RIGHT:
679                diff = w-leftover;
680                dx = x+w-leftover;
681                dy = y;
682                dw = leftover;
683                dh = h;
684                break;
685        default:
686                /*fix warning*/ dx = dy = dw = dh = 0;
687                diff = 1;
688                g_assert_not_reached();
689                break;
690        }
691
692        if(!pw_disable_animations && step != 0) {
693                GTimeVal tval;
694                long start_secs;
695                long start_time;
696                long end_time;
697                long cur_time;
698
699                g_get_current_time(&tval);
700               
701                start_secs = tval.tv_sec;
702                start_time = tval.tv_usec;
703               
704                end_time = start_time +
705                        (diff/1000.0)*200*(10001-(step*step));
706
707                basep_widget_set_ebox_orient(basep, hide_orient);
708
709                while(x != dx ||
710                      y != dy ||
711                      w != dw ||
712                      h != dh) {
713                        g_get_current_time(&tval);
714                       
715                        cur_time = ((tval.tv_sec-start_secs)*1000000) +
716                                tval.tv_usec;
717
718                        x = move_step(ox,dx,start_time,end_time,cur_time);
719                        y = move_step(oy,dy,start_time,end_time,cur_time);
720                        w = move_step(ow,dw,start_time,end_time,cur_time);
721                        h = move_step(oh,dh,start_time,end_time,cur_time);
722                        gdk_window_move_resize(wid->window, x,y,w,h);
723                        gdk_flush();
724                        usleep(1000);
725                }
726
727                xstuff_set_pos_size (wid->window,
728                                     dx, dy, dw, dh);
729                basep_widget_set_ebox_orient(basep, -1);
730        }
731       
732        gtk_widget_queue_resize(wid);
733        gtk_widget_draw(basep->table, NULL);
734}
735
736void
737basep_widget_do_showing(BasePWidget *basep, PanelOrientType hide_orient,
738                        int leftover, int step)
739{
740        GtkWidget *wid;
741        int x,y, dx,dy, ox,oy;
742        int w,h, dw,dh, ow,oh;
743        int diff;
744
745        g_return_if_fail(basep != NULL);
746        g_return_if_fail(IS_BASEP_WIDGET(basep));
747
748        if (basep->state != BASEP_MOVING) {
749#ifdef PANEL_DEBUG
750                g_warning ("do_showing whilst not moving");
751#endif
752                return;
753        }
754
755        wid = GTK_WIDGET(basep);
756       
757        ox = dx = x = basep->shown_alloc.x;
758        oy = dy = y = basep->shown_alloc.y;
759        dw = basep->shown_alloc.width;
760        dh = basep->shown_alloc.height;
761                             
762        switch(hide_orient) {
763        case ORIENT_UP:
764                ow = w = dw;
765                oh = h = leftover;
766                diff = dh-leftover;
767                break;
768        case ORIENT_DOWN:
769                oy = y + dh - leftover;
770                ow = w = dw;
771                oh = h = leftover;
772                diff = dh-leftover;
773                break;
774        case ORIENT_LEFT:
775                ow = w = leftover;
776                oh = h = dh;
777                diff = dw-leftover;
778                break;
779        case ORIENT_RIGHT:
780                ox = x + dw - leftover;
781                ow = w = leftover;
782                oh = h = dh;
783                diff = dw-leftover;
784                break;
785        default:
786                /*fix warning*/ dx = dy = ow = oh = w = h = 0;
787                diff = 1;
788                g_assert_not_reached();
789                break;
790        }
791       
792        if(!pw_disable_animations && step != 0) {
793                int i;
794                GTimeVal tval;
795                long start_secs;
796                long start_time;
797                long end_time;
798                long cur_time;
799
800                g_get_current_time(&tval);
801               
802                start_secs = tval.tv_sec;
803                start_time = tval.tv_usec;
804               
805                end_time = start_time +
806                        (diff/1000.0)*200*(10001-(step*step));
807               
808                basep_widget_set_ebox_orient(basep, hide_orient);
809                gdk_window_show(wid->window);
810                xstuff_set_pos_size (wid->window,
811                                     ox, oy, ow, oh);
812
813                gtk_widget_show_now(wid);
814
815                gdk_window_show(wid->window);
816                i = 0;
817                while(x != dx ||
818                      y != dy ||
819                      w != dw ||
820                      h != dh) {
821                        g_get_current_time(&tval);
822                       
823                        cur_time = ((tval.tv_sec-start_secs)*1000000) +
824                                tval.tv_usec;
825                       
826                        x = move_step(ox,dx,start_time,end_time,cur_time);
827                        y = move_step(oy,dy,start_time,end_time,cur_time);
828                        w = move_step(ow,dw,start_time,end_time,cur_time);
829                        h = move_step(oh,dh,start_time,end_time,cur_time);
830                        gdk_window_move_resize(wid->window, x,y,w,h);
831                        gdk_flush();
832                       
833                        /*drawing the entire table flickers, so don't
834                          do it often*/
835                        if(i++%10)
836                                gtk_widget_draw(basep->panel, NULL);
837                        else
838                                gtk_widget_draw(basep->table, NULL);
839                        gdk_flush();
840                        usleep(1000);
841                }
842
843                xstuff_set_pos_size (wid->window,
844                                     dx, dy, dw, dh);
845
846                basep_widget_set_ebox_orient(basep, -1);
847        }
848       
849        gtk_widget_draw(basep->table, NULL);
850        gtk_widget_queue_resize(wid);
851}
852
853
854static GtkWidget *
855make_hidebutton(BasePWidget *basep,
856                char *pixmaparrow,
857                int horizontal)
858{
859        GtkWidget *w;
860        GtkWidget *pixmap;
861        char *pixmap_name;
862
863        w = gtk_button_new();
864        GTK_WIDGET_UNSET_FLAGS(w, GTK_CAN_DEFAULT|GTK_CAN_FOCUS);
865        if(horizontal)
866                gtk_widget_set_usize(w, 0, PANEL_MINIMUM_WIDTH);
867        else
868                gtk_widget_set_usize(w, PANEL_MINIMUM_WIDTH, 0);
869
870        pixmap_name=gnome_pixmap_file(pixmaparrow);
871        if(pixmap_name) {
872                pixmap = gnome_pixmap_new_from_file(pixmap_name);
873                g_free(pixmap_name);
874        } else {
875                pixmap = gtk_label_new("*");
876        }
877        gtk_widget_show(pixmap);
878
879        gtk_container_add(GTK_CONTAINER(w),pixmap);
880        gtk_object_set_user_data(GTK_OBJECT(w), pixmap);
881        gtk_object_set_data(GTK_OBJECT(w), "gnome_disable_sound_events",
882                            GINT_TO_POINTER(1));
883
884        gtk_tooltips_set_tip (panel_tooltips, w,
885                              _("Hide/unhide this panel"), NULL);
886
887        return w;
888}
889
890static void
891basep_widget_destroy (GtkObject *o)
892{
893        BasePWidget *basep = BASEP_WIDGET (o);
894        /* check if there's a timeout set, and delete it if
895         * there was */
896        if (basep->leave_notify_timer_tag != 0)
897                gtk_timeout_remove (basep->leave_notify_timer_tag);
898        basep->leave_notify_timer_tag = 0;
899
900        if (IS_BORDER_WIDGET (basep))
901                basep_border_queue_recalc (basep->screen);
902
903        gtk_object_unref (GTK_OBJECT (basep->pos));
904        basep->pos = NULL;
905
906        if (GTK_OBJECT_CLASS (basep_widget_parent_class)->destroy)
907                GTK_OBJECT_CLASS (basep_widget_parent_class)->destroy (o);
908}       
909
910static void
911reparent_button_widgets(GtkWidget *w, gpointer data)
912{
913        GdkWindow *newwin = data;
914        if(IS_BUTTON_WIDGET(w)) {
915                ButtonWidget *button = BUTTON_WIDGET(w);
916                /* we can just reparent them all to 0,0 as the next thing
917                 * that will happen is a queue_resize and on size allocate
918                 * they will be put into their proper place */
919                gdk_window_reparent(button->event_window, newwin, 0, 0);
920        }
921}
922
923void
924basep_widget_redo_window(BasePWidget *basep)
925{
926        GtkWindow *window;
927        GtkWidget *widget;
928        GdkWindowAttr attributes;
929        gint attributes_mask;
930        GdkWindow *oldwin;
931        GdkWindow *newwin;
932        gboolean comp;
933
934        comp = xstuff_is_compliant_wm();
935        if(comp == basep->compliant_wm)
936                return;
937
938        window = GTK_WINDOW(basep);
939        widget = GTK_WIDGET(basep);
940
941        basep->compliant_wm = comp;
942        if(basep->compliant_wm) {
943                window->type = GTK_WINDOW_TOPLEVEL;
944                attributes.window_type = GDK_WINDOW_TOPLEVEL;
945        } else {
946                window->type = GTK_WINDOW_POPUP;
947                attributes.window_type = GDK_WINDOW_TEMP;
948        }
949
950        if(!widget->window)
951                return;
952
953        /* this is mostly copied from gtkwindow.c realize method */
954        attributes.title = window->title;
955        attributes.wmclass_name = window->wmclass_name;
956        attributes.wmclass_class = window->wmclass_class;
957        attributes.width = widget->allocation.width;
958        attributes.height = widget->allocation.height;
959        attributes.wclass = GDK_INPUT_OUTPUT;
960        attributes.visual = gtk_widget_get_visual (widget);
961        attributes.colormap = gtk_widget_get_colormap (widget);
962        attributes.event_mask = gtk_widget_get_events (widget);
963        attributes.event_mask |= (GDK_EXPOSURE_MASK |
964                                  GDK_KEY_PRESS_MASK |
965                                  GDK_ENTER_NOTIFY_MASK |
966                                  GDK_LEAVE_NOTIFY_MASK |
967                                  GDK_FOCUS_CHANGE_MASK |
968                                  GDK_STRUCTURE_MASK);
969
970        attributes_mask = GDK_WA_VISUAL | GDK_WA_COLORMAP;
971        attributes_mask |= (window->title ? GDK_WA_TITLE : 0);
972        attributes_mask |= (window->wmclass_name ? GDK_WA_WMCLASS : 0);
973   
974        oldwin = widget->window;
975
976        newwin = gdk_window_new(NULL, &attributes, attributes_mask);
977        gdk_window_set_user_data(newwin, window);
978
979        xstuff_set_no_group_and_no_input (newwin);
980
981        /* reparent our main panel window */
982        gdk_window_reparent(basep->ebox->window, newwin, 0, 0);
983        /* reparent all the base event windows as they are also children of
984         * the basep */
985        gtk_container_foreach(GTK_CONTAINER(basep->panel),
986                              reparent_button_widgets,
987                              newwin);
988
989
990        widget->window = newwin;
991
992        gdk_window_set_user_data(oldwin, NULL);
993        gdk_window_destroy(oldwin);
994
995        widget->style = gtk_style_attach(widget->style, widget->window);
996        gtk_style_set_background(widget->style, widget->window, GTK_STATE_NORMAL);
997
998        GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
999
1000        gtk_widget_queue_resize(widget);
1001
1002        basep_widget_update_winhints (basep);
1003
1004        gtk_drag_dest_set (widget, 0, NULL, 0, 0);
1005
1006        gtk_widget_map(widget);
1007}
1008
1009
1010static void
1011basep_widget_init (BasePWidget *basep)
1012{
1013        basep->screen = 0;
1014
1015        /*if we set the gnomewm hints it will have to be changed to TOPLEVEL*/
1016        basep->compliant_wm = xstuff_is_compliant_wm();
1017        if(basep->compliant_wm)
1018                GTK_WINDOW(basep)->type = GTK_WINDOW_TOPLEVEL;
1019        else
1020                GTK_WINDOW(basep)->type = GTK_WINDOW_POPUP;
1021
1022        GTK_WINDOW(basep)->allow_shrink = TRUE;
1023        GTK_WINDOW(basep)->allow_grow = TRUE;
1024        GTK_WINDOW(basep)->auto_shrink = TRUE;
1025
1026        /*don't let us close the window*/                                       
1027       
1028        gtk_signal_connect(GTK_OBJECT(basep),"delete_event",                   
1029                           GTK_SIGNAL_FUNC(gtk_true),NULL);                     
1030
1031        basep->shown_alloc.x = basep->shown_alloc.y =
1032                basep->shown_alloc.width = basep->shown_alloc.height = 0;
1033       
1034        /*this makes the popup "pop down" once the button is released*/
1035        gtk_widget_set_events(GTK_WIDGET(basep),
1036                              gtk_widget_get_events(GTK_WIDGET(basep)) |
1037                              GDK_BUTTON_RELEASE_MASK);
1038
1039        basep->ebox = gtk_event_box_new();
1040        gtk_container_add(GTK_CONTAINER(basep),basep->ebox);
1041        gtk_widget_show(basep->ebox);
1042
1043        basep->table = gtk_table_new(3,3,FALSE);
1044        gtk_container_add(GTK_CONTAINER(basep->ebox),basep->table);
1045        gtk_widget_show(basep->table);
1046
1047        basep->frame = gtk_frame_new(NULL);
1048        gtk_frame_set_shadow_type(GTK_FRAME(basep->frame),GTK_SHADOW_OUT);
1049
1050        gtk_table_attach(GTK_TABLE(basep->table),basep->frame,1,2,1,2,
1051                         GTK_FILL|GTK_EXPAND|GTK_SHRINK,
1052                         GTK_FILL|GTK_EXPAND|GTK_SHRINK,
1053                         0,0);
1054
1055        basep->innerebox = gtk_event_box_new();
1056
1057        gtk_table_attach(GTK_TABLE(basep->table),basep->innerebox,1,2,1,2,
1058                         GTK_FILL|GTK_EXPAND|GTK_SHRINK,
1059                         GTK_FILL|GTK_EXPAND|GTK_SHRINK,
1060                         0,0);
1061
1062        basep->mode = BASEP_EXPLICIT_HIDE;
1063        basep->state = BASEP_SHOWN;
1064        basep->level = BASEP_LEVEL_DEFAULT;
1065        basep->avoid_on_maximize = TRUE;
1066        basep->leave_notify_timer_tag = 0;
1067        basep->autohide_inhibit = FALSE;
1068        basep->drawers_open = 0;
1069
1070        basep->hidebuttons_enabled = TRUE;
1071        basep->hidebutton_pixmaps_enabled = TRUE;
1072}
1073
1074static void
1075show_hidebutton_pixmap(GtkWidget *hidebutton, int show)
1076{
1077        GtkWidget *pixmap;
1078
1079        pixmap = gtk_object_get_user_data(GTK_OBJECT(hidebutton));
1080
1081        if (!pixmap) return;
1082
1083        if (show)
1084                gtk_widget_show(pixmap);
1085        else
1086                gtk_widget_hide(pixmap);
1087}
1088
1089static void
1090basep_widget_show_hidebutton_pixmaps(BasePWidget *basep)
1091{
1092        int show = basep->hidebutton_pixmaps_enabled;
1093        show_hidebutton_pixmap(basep->hidebutton_n, show);
1094        show_hidebutton_pixmap(basep->hidebutton_e, show);
1095        show_hidebutton_pixmap(basep->hidebutton_w, show);
1096        show_hidebutton_pixmap(basep->hidebutton_s, show);
1097}
1098
1099void
1100basep_widget_update_winhints (BasePWidget *basep)
1101{
1102        GtkWidget *w = GTK_WIDGET (basep);
1103        GnomeWinLayer layer;
1104        guint coverhint;
1105
1106        /* Do this before compliance check, the compliance
1107         * check is for the legacy GNOME spec, this is for the
1108         * new WM spec. Also, there's no harm to setting the hint
1109         * for incompliant WM's, they'll just ignore it.
1110         */
1111        xstuff_set_wmspec_dock_hints (w->window);
1112       
1113        if ( ! basep->compliant_wm)
1114                return;
1115
1116        gnome_win_hints_set_expanded_size (w, 0, 0, 0, 0);
1117        gdk_window_set_decorations (w->window, 0);
1118        gnome_win_hints_set_state (w, WIN_STATE_STICKY |
1119                                   WIN_STATE_FIXED_POSITION);
1120
1121        if (basep->avoid_on_maximize) {
1122                coverhint = WIN_HINTS_DO_NOT_COVER;
1123        } else {
1124                coverhint = 0;
1125        }
1126
1127        if (basep->level == BASEP_LEVEL_DEFAULT) {
1128                if (global_config.normal_layer) {
1129                        layer = WIN_LAYER_NORMAL;
1130                } else if (global_config.keep_bottom) {
1131                        layer = WIN_LAYER_BELOW;
1132                } else {
1133                        layer = WIN_LAYER_DOCK;
1134                }
1135
1136                /* drawers are always in DOCK, or NORMAL */
1137                if ( IS_DRAWER_WIDGET(w) &&
1138                     ! global_config.normal_layer)
1139                        layer = WIN_LAYER_DOCK;
1140
1141                /* if in autohiding mode, then we always want dock by default
1142                 */
1143                if (basep->mode == BASEP_AUTO_HIDE)
1144                        layer = WIN_LAYER_DOCK;
1145
1146        } else if (basep->level == BASEP_LEVEL_BELOW) {
1147                layer = WIN_LAYER_BELOW;
1148        } else if (basep->level == BASEP_LEVEL_NORMAL) {
1149                layer = WIN_LAYER_NORMAL;
1150        } else /* if (basep->level == BASEP_LEVEL_ABOVE) */ {
1151                layer = WIN_LAYER_DOCK;
1152        }
1153
1154        switch (basep->state) {
1155        case BASEP_SHOWN:
1156        case BASEP_MOVING:
1157
1158                gnome_win_hints_set_layer (w, layer);
1159                gnome_win_hints_set_hints (w, GNOME_PANEL_HINTS |
1160                                           coverhint);
1161                break;
1162        default: /* all of the hidden states */
1163                gnome_win_hints_set_hints (w, GNOME_PANEL_HINTS);
1164                gnome_win_hints_set_layer (w, (global_config.keep_bottom ||
1165                                               global_config.normal_layer)
1166                                           ? WIN_LAYER_ONTOP
1167                                           : WIN_LAYER_ABOVE_DOCK);
1168                break;
1169        }
1170}
1171
1172void
1173basep_update_frame (BasePWidget *basep)
1174{
1175        gboolean hide_frame = global_config.hide_panel_frame ||
1176                PANEL_WIDGET (basep->panel)->back_type ==
1177                                                PANEL_BACK_TRANSLUCENT ||
1178                PANEL_WIDGET (basep->panel)->back_type == PANEL_BACK_PIXMAP;
1179
1180        if (hide_frame && GTK_WIDGET_VISIBLE (basep->frame)) {
1181                gtk_widget_show (basep->innerebox);
1182                gtk_widget_reparent (basep->panel, basep->innerebox);
1183                gtk_widget_hide (basep->frame);
1184        } else if (!hide_frame && !GTK_WIDGET_VISIBLE (basep->frame)) {
1185                gtk_widget_show (basep->frame);
1186                gtk_widget_reparent (basep->panel, basep->frame);
1187                gtk_widget_hide (basep->innerebox);
1188        }
1189}
1190
1191static void
1192basep_back_change (PanelWidget *panel,
1193                   PanelBackType type,
1194                   char *pixmap,
1195                   GdkColor *color,
1196                   BasePWidget *basep)
1197{
1198        basep_update_frame (basep);
1199
1200        set_frame_colors (panel,
1201                          basep->frame,
1202                          basep->hidebutton_n,
1203                          basep->hidebutton_e,
1204                          basep->hidebutton_w,
1205                          basep->hidebutton_s);
1206}
1207
1208static void
1209basep_style_set (GtkWidget *widget, GtkStyle *previous_style)
1210{
1211        BasePWidget *basep;
1212        PanelWidget *panel;
1213
1214        g_return_if_fail (widget != NULL);
1215        g_return_if_fail (IS_BASEP_WIDGET (widget));
1216
1217        basep = BASEP_WIDGET (widget);
1218
1219        g_return_if_fail (basep->panel != NULL);
1220        g_return_if_fail (IS_PANEL_WIDGET (basep->panel));
1221
1222        panel = PANEL_WIDGET (basep->panel);
1223
1224        if (GTK_WIDGET_CLASS (basep_widget_parent_class)->style_set)
1225                GTK_WIDGET_CLASS (basep_widget_parent_class)->style_set (widget, previous_style);
1226
1227        set_frame_colors (panel,
1228                          basep->frame,
1229                          basep->hidebutton_n,
1230                          basep->hidebutton_e,
1231                          basep->hidebutton_w,
1232                          basep->hidebutton_s);
1233}
1234
1235static void
1236basep_widget_north_clicked (GtkWidget *widget, gpointer data)
1237{
1238        BasePWidget *basep = data;
1239        BasePPosClass *klass =
1240                basep_widget_get_pos_class (basep);
1241
1242        gtk_widget_set_state (widget, GTK_STATE_NORMAL);
1243        gtk_widget_queue_draw (widget);
1244
1245        if (klass && klass->north_clicked)
1246                klass->north_clicked(basep);
1247}
1248
1249static void
1250basep_widget_south_clicked (GtkWidget *widget, gpointer data)
1251{
1252        BasePWidget *basep = data;
1253        BasePPosClass *klass =
1254                basep_widget_get_pos_class (basep);
1255
1256        gtk_widget_set_state (widget, GTK_STATE_NORMAL);
1257        gtk_widget_queue_draw (widget);
1258       
1259        if (klass && klass->south_clicked)
1260                klass->south_clicked(basep);
1261}
1262
1263static void
1264basep_widget_east_clicked (GtkWidget *widget, gpointer data)
1265{
1266        BasePWidget *basep = data;
1267        BasePPosClass *klass =
1268                basep_widget_get_pos_class (basep);
1269
1270        gtk_widget_set_state (widget, GTK_STATE_NORMAL);
1271        gtk_widget_queue_draw (widget);
1272       
1273        if (klass && klass->east_clicked)
1274                klass->east_clicked(basep);
1275}
1276
1277static void
1278basep_widget_west_clicked (GtkWidget *widget, gpointer data)
1279{
1280        BasePWidget *basep = data;
1281        BasePPosClass *klass =
1282                basep_widget_get_pos_class (basep);
1283
1284        gtk_widget_set_state (widget, GTK_STATE_NORMAL);
1285        gtk_widget_queue_draw (widget);
1286       
1287        if (klass && klass->west_clicked)
1288                klass->west_clicked(basep);
1289}
1290
1291GtkWidget*
1292basep_widget_construct (BasePWidget *basep,
1293                        gboolean packed,
1294                        gboolean reverse_arrows,
1295                        int screen,
1296                        PanelOrientation orient,
1297                        int sz,
1298                        BasePMode mode,
1299                        BasePState state,
1300                        BasePLevel level,
1301                        gboolean avoid_on_maximize,
1302                        gboolean hidebuttons_enabled,
1303                        gboolean hidebutton_pixmaps_enabled,
1304                        PanelBackType back_type,
1305                        char *back_pixmap,
1306                        gboolean fit_pixmap_bg,
1307                        gboolean strech_pixmap_bg,
1308                        gboolean rotate_pixmap_bg,
1309                        GdkColor *back_color)
1310{
1311        BasePPosClass *klass = basep_widget_get_pos_class (basep);
1312        int x = 0, y = 0;
1313        basep->panel = panel_widget_new(packed,
1314                                        orient,
1315                                        sz,
1316                                        back_type,
1317                                        back_pixmap,
1318                                        fit_pixmap_bg,
1319                                        strech_pixmap_bg,
1320                                        rotate_pixmap_bg,
1321                                        /*if hidebuttons are enabled, then
1322                                          do no padding on the sides */
1323                                        !hidebuttons_enabled,
1324                                        back_color);
1325
1326        gtk_signal_connect_after(GTK_OBJECT(basep->panel), "back_change",
1327                                 GTK_SIGNAL_FUNC(basep_back_change),
1328                                 basep);
1329
1330        PANEL_WIDGET(basep->panel)->panel_parent = GTK_WIDGET(basep);
1331        PANEL_WIDGET(basep->panel)->drop_widget = GTK_WIDGET(basep);
1332
1333        gtk_widget_show(basep->panel);
1334
1335        if(back_type != PANEL_BACK_PIXMAP &&
1336                        back_type != PANEL_BACK_TRANSLUCENT &&
1337                        !global_config.hide_panel_frame) {
1338                gtk_widget_show(basep->frame);
1339                gtk_container_add(GTK_CONTAINER(basep->frame),basep->panel);
1340        } else {
1341                gtk_widget_show(basep->innerebox);
1342                gtk_container_add(GTK_CONTAINER(basep->innerebox),basep->panel);
1343        }
1344
1345        /*we add all the hide buttons to the table here*/
1346        /*WEST*/
1347        basep->hidebutton_w = make_hidebutton(basep,
1348                                              reverse_arrows?
1349                                              "panel-arrow-right.png":
1350                                              "panel-arrow-left.png",
1351                                              TRUE);
1352        gtk_table_attach(GTK_TABLE(basep->table),basep->hidebutton_w,
1353                         0,1,1,2,GTK_FILL,GTK_FILL,0,0);
1354        gtk_signal_connect (GTK_OBJECT(basep->hidebutton_w), "clicked",
1355                            GTK_SIGNAL_FUNC (basep_widget_west_clicked),
1356                            basep);
1357        /*NORTH*/
1358        basep->hidebutton_n = make_hidebutton(basep,
1359                                              reverse_arrows?
1360                                              "panel-arrow-down.png":
1361                                              "panel-arrow-up.png",
1362                                              FALSE);
1363        gtk_table_attach(GTK_TABLE(basep->table),basep->hidebutton_n,
1364                         1,2,0,1,GTK_FILL,GTK_FILL,0,0);
1365        gtk_signal_connect (GTK_OBJECT(basep->hidebutton_n), "clicked",
1366                            GTK_SIGNAL_FUNC (basep_widget_north_clicked),
1367                            basep);
1368        /*EAST*/
1369        basep->hidebutton_e = make_hidebutton(basep,
1370                                              reverse_arrows?
1371                                              "panel-arrow-left.png":
1372                                              "panel-arrow-right.png",
1373                                              TRUE);
1374        gtk_table_attach(GTK_TABLE(basep->table),basep->hidebutton_e,
1375                         2,3,1,2,GTK_FILL,GTK_FILL,0,0);
1376        gtk_signal_connect (GTK_OBJECT(basep->hidebutton_e), "clicked",
1377                            GTK_SIGNAL_FUNC (basep_widget_east_clicked),
1378                            basep);
1379        /*SOUTH*/
1380        basep->hidebutton_s = make_hidebutton (basep,
1381                                              reverse_arrows ?
1382                                              "panel-arrow-up.png" :
1383                                              "panel-arrow-down.png",
1384                                              FALSE);
1385        gtk_table_attach(GTK_TABLE(basep->table), basep->hidebutton_s,
1386                         1, 2, 2, 3, GTK_FILL, GTK_FILL, 0, 0);
1387        gtk_signal_connect (GTK_OBJECT(basep->hidebutton_s), "clicked",
1388                            GTK_SIGNAL_FUNC (basep_widget_south_clicked),
1389                            basep);
1390
1391        basep->screen = screen;
1392
1393        basep->level = level;
1394        basep->avoid_on_maximize = avoid_on_maximize;
1395
1396        basep->hidebuttons_enabled = hidebuttons_enabled;
1397        basep->hidebutton_pixmaps_enabled = hidebutton_pixmaps_enabled;
1398
1399        basep_widget_set_hidebuttons (basep);
1400        basep_widget_show_hidebutton_pixmaps (basep);
1401
1402        basep->mode = mode;
1403        basep->state = state;
1404
1405        basep->pos->basep = basep;
1406
1407        if (state == BASEP_AUTO_HIDDEN &&
1408            mode != BASEP_AUTO_HIDE)
1409                basep->state = BASEP_SHOWN;
1410               
1411        if (klass->get_pos)
1412                klass->get_pos (basep, &x, &y,
1413                                PANEL_MINIMUM_WIDTH,
1414                                PANEL_MINIMUM_WIDTH);
1415        gtk_widget_set_uposition (GTK_WIDGET (basep), x, y);
1416       
1417        return GTK_WIDGET (basep);
1418}
1419
1420void
1421basep_widget_change_params (BasePWidget *basep,
1422                            int screen,
1423                            PanelOrientation orient,
1424                            int sz,
1425                            BasePMode mode,
1426                            BasePState state,
1427                            BasePLevel level,
1428                            gboolean avoid_on_maximize,
1429                            gboolean hidebuttons_enabled,
1430                            gboolean hidebutton_pixmaps_enabled,
1431                            PanelBackType back_type,
1432                            char *pixmap_name,
1433                            gboolean fit_pixmap_bg,
1434                            gboolean strech_pixmap_bg,
1435                            gboolean rotate_pixmap_bg,
1436                            GdkColor *back_color)
1437{
1438        g_return_if_fail(basep);
1439        g_return_if_fail(GTK_WIDGET_REALIZED(GTK_WIDGET(basep)));
1440
1441        if (PANEL_WIDGET (basep->panel)->orient != orient)
1442                basep->request_cube = TRUE;
1443       
1444        basep->hidebuttons_enabled = hidebuttons_enabled;
1445        basep->hidebutton_pixmaps_enabled = hidebutton_pixmaps_enabled;
1446
1447#if 0
1448        if (type != basep->type)
1449                basep_widget_convert_to (basep, type);
1450#endif
1451
1452        if (state == BASEP_AUTO_HIDDEN &&
1453            mode != BASEP_AUTO_HIDE)
1454                state = BASEP_SHOWN;
1455
1456        if (mode != basep->mode) {
1457                basep->mode = mode;
1458                if (mode == BASEP_AUTO_HIDE)
1459                        basep_widget_queue_autohide (basep);
1460                gtk_signal_emit(GTK_OBJECT(basep),
1461                                basep_widget_signals[MODE_CHANGE_SIGNAL],
1462                                mode);
1463        }
1464       
1465        if (state != basep->state) {
1466                basep->state = state;
1467                if (state != BASEP_AUTO_HIDDEN)
1468                        basep_widget_autoshow (basep);
1469                gtk_signal_emit(GTK_OBJECT(basep),
1470                                basep_widget_signals[STATE_CHANGE_SIGNAL],
1471                                state);
1472                panels_to_sync = TRUE;
1473        }
1474
1475        panel_widget_change_params(PANEL_WIDGET(basep->panel),
1476                                   orient,
1477                                   sz,
1478                                   back_type,
1479                                   pixmap_name,
1480                                   fit_pixmap_bg,
1481                                   strech_pixmap_bg,
1482                                   rotate_pixmap_bg,
1483                                   /*if hidebuttons are enabled, then
1484                                     do no padding on the sides */
1485                                   !hidebuttons_enabled,
1486                                   back_color);
1487
1488        if (basep->level != level ||
1489            basep->avoid_on_maximize != avoid_on_maximize) {
1490                basep->level = level;
1491                basep->avoid_on_maximize = avoid_on_maximize;
1492                basep_widget_update_winhints (basep);
1493        }
1494
1495        basep_widget_set_hidebuttons (basep);
1496        basep_widget_show_hidebutton_pixmaps (basep);
1497
1498        basep_widget_screen_change (basep, screen);
1499
1500        gtk_widget_queue_resize (GTK_WIDGET (basep));
1501}
1502
1503#if 0
1504gboolean
1505basep_widget_convert_to (BasePWidget *basep,
1506                         PanelType type)
1507{
1508        BasePPosClass *klass =
1509                basep_widget_get_pos_class (basep);
1510        BasePPos *old_pos, *new_pos;
1511        gint16 x=0, y=0;
1512        gboolean temp_keep;
1513
1514        g_return_val_if_fail (IS_BASEP_WIDGET(basep), FALSE);
1515
1516        g_return_val_if_fail (create_panel_type[type], FALSE);
1517
1518        basep_widget_get_pos(basep, &x, &y);
1519
1520        old_pos = basep->pos;
1521        new_pos = gtk_type_new (create_panel_type[type] ());
1522
1523        if (!new_pos)
1524                return FALSE;
1525
1526        basep->pos = new_pos;
1527        new_pos->basep = basep;
1528
1529        gtk_object_unref (GTK_OBJECT (old_pos));
1530
1531        klass = basep_widget_get_pos_class (basep);
1532        if (klass->pre_convert_hook)
1533                klass->pre_convert_hook (basep);
1534
1535        temp_keep = basep->keep_in_screen;
1536        basep->keep_in_screen = FALSE;
1537        gtk_widget_set_uposition (GTK_WIDGET (basep), -100, -100);
1538        gdk_flush ();
1539        basep_widget_set_pos (basep, -100, -100);
1540        gdk_flush ();
1541        g_print ("-------------------------------------\n");
1542        basep_widget_set_pos (basep, x, y);
1543        basep->keep_in_screen = temp_keep;
1544        gtk_signal_emit (GTK_OBJECT(basep),
1545                         basep_widget_signals[TYPE_CHANGE_SIGNAL],
1546                         type);
1547
1548        /*gtk_widget_queue_resize (GTK_WIDGET (basep));*/
1549        return TRUE;
1550}
1551#endif
1552
1553void
1554basep_widget_enable_buttons_ (BasePWidget *basep, gboolean enabled)
1555{
1556        gtk_widget_set_sensitive(basep->hidebutton_n, enabled);
1557        gtk_widget_set_sensitive(basep->hidebutton_e, enabled);
1558        gtk_widget_set_sensitive(basep->hidebutton_w, enabled);
1559        gtk_widget_set_sensitive(basep->hidebutton_s, enabled);
1560}
1561
1562void
1563basep_widget_set_hidebuttons (BasePWidget *basep)
1564{
1565        BasePPosClass *klass = basep_widget_get_pos_class (basep);
1566        if (!basep->hidebuttons_enabled) {
1567                gtk_widget_hide(basep->hidebutton_n);
1568                gtk_widget_hide(basep->hidebutton_e);
1569                gtk_widget_hide(basep->hidebutton_w);
1570                gtk_widget_hide(basep->hidebutton_s);   
1571
1572                /* if we removed hidebuttons we need to show ourselves,
1573                 * except for the drawers case that is */
1574                if ((basep->state == BASEP_HIDDEN_LEFT ||
1575                     basep->state == BASEP_HIDDEN_RIGHT) &&
1576                    ! IS_DRAWER_WIDGET (basep))
1577                        basep_widget_explicit_show (basep);
1578        } else {
1579                g_return_if_fail (klass && klass->set_hidebuttons);
1580                klass->set_hidebuttons(basep);
1581        }
1582}
1583
1584void
1585basep_widget_explicit_hide (BasePWidget *basep, BasePState state)
1586{
1587        static const char *supinfo[] = {"panel", "collapse", NULL};
1588
1589        g_assert ( (state == BASEP_HIDDEN_RIGHT) ||
1590                   (state == BASEP_HIDDEN_LEFT) );
1591
1592        if((basep->state != BASEP_SHOWN))
1593                return;
1594
1595        if (basep->state == BASEP_MOVING) {
1596#ifdef PANEL_DEBUG
1597                g_warning ("explicit_hide whilst moving");
1598#endif
1599                return;
1600        }
1601
1602        gnome_triggers_vdo("", NULL, supinfo);
1603
1604        gtk_signal_emit(GTK_OBJECT(basep),
1605                        basep_widget_signals[STATE_CHANGE_SIGNAL],
1606                        state);
1607        panels_to_sync = TRUE;
1608
1609        /* if the app did any updating of the interface, flush that for us*/
1610        gdk_flush();
1611       
1612        if (GTK_WIDGET_REALIZED(GTK_WIDGET(basep))) {
1613                BasePPosClass *klass = basep_widget_get_pos_class (basep);
1614                PanelOrientType hide_orient;
1615                int w, h, size;
1616
1617                basep->state = state;
1618               
1619                hide_orient = klass->get_hide_orient (basep);
1620                basep_widget_get_size (basep, &w, &h);
1621                klass->get_hide_size (basep,
1622                                      hide_orient,
1623                                      &w, &h);
1624
1625                size = (hide_orient == ORIENT_UP ||
1626                        hide_orient == ORIENT_DOWN) ?
1627                        h : w;
1628               
1629                basep->state = BASEP_MOVING;
1630                basep_widget_update_winhints (basep);
1631                basep_widget_do_hiding (basep, hide_orient,
1632                                        size, pw_explicit_step);
1633        }
1634
1635        basep->state = state;
1636        basep_widget_update_winhints (basep);
1637}
1638
1639void
1640basep_widget_explicit_show (BasePWidget *basep)
1641{
1642        static const char *supinfo[] = {"panel", "expand", NULL};
1643
1644        if ( (basep->state != BASEP_HIDDEN_LEFT &&
1645              basep->state != BASEP_HIDDEN_RIGHT))
1646                return;
1647 
1648        if (basep->state == BASEP_MOVING) {
1649#ifdef PANEL_DEBUG
1650                g_warning ("explicit_show whilst moving");
1651#endif
1652                return;
1653        }
1654
1655        gnome_triggers_vdo("", NULL, supinfo);
1656
1657        if (GTK_WIDGET_REALIZED(GTK_WIDGET(basep))) {
1658                BasePPosClass *klass = basep_widget_get_pos_class (basep);
1659                PanelOrientType hide_orient;
1660                int w, h, size;
1661
1662                hide_orient = klass->get_hide_orient (basep);
1663                basep_widget_get_size (basep, &w, &h);
1664                klass->get_hide_size (basep,
1665                                      hide_orient,
1666                                      &w, &h);
1667
1668                size = (hide_orient == ORIENT_UP ||
1669                        hide_orient == ORIENT_DOWN) ?
1670                        h : w;
1671
1672                basep->state = BASEP_MOVING;
1673                basep_widget_update_winhints (basep);
1674                basep_widget_do_showing (basep, hide_orient,
1675                                         size, pw_explicit_step);
1676        }
1677       
1678        basep->state = BASEP_SHOWN;
1679        basep_widget_update_winhints (basep);
1680
1681        gtk_signal_emit(GTK_OBJECT(basep),
1682                        basep_widget_signals[STATE_CHANGE_SIGNAL],
1683                        BASEP_SHOWN);
1684        panels_to_sync = TRUE;
1685}
1686
1687gboolean
1688basep_widget_autoshow (gpointer data)
1689{
1690        BasePWidget *basep = data;
1691        static const char *supinfo[] = {"panel", "expand", NULL};
1692
1693        g_return_val_if_fail (IS_BASEP_WIDGET(basep), FALSE);
1694
1695        if (basep->state == BASEP_MOVING) {
1696#ifdef PANEL_DEBUG
1697                g_warning ("autoshow whilst moving");
1698#endif
1699                return TRUE;
1700        }
1701       
1702        if ( (basep->mode != BASEP_AUTO_HIDE) ||
1703             (basep->state != BASEP_AUTO_HIDDEN))
1704                return TRUE;
1705
1706        if (GTK_WIDGET_REALIZED(basep)) {
1707                BasePPosClass *klass = basep_widget_get_pos_class (basep);
1708                PanelOrientType hide_orient;
1709                int w, h, size;
1710
1711                gnome_triggers_vdo("", NULL, supinfo);
1712
1713                hide_orient = klass->get_hide_orient (basep);
1714                basep_widget_get_size (basep, &w, &h);
1715                klass->get_hide_size (basep,
1716                                      hide_orient,
1717                                      &w, &h);
1718
1719                size = (hide_orient == ORIENT_UP ||
1720                        hide_orient == ORIENT_DOWN) ?
1721                        h : w;
1722
1723                basep->state = BASEP_MOVING;
1724                basep_widget_update_winhints (basep);
1725                basep_widget_do_showing (basep,
1726                                         hide_orient,
1727                                         size,
1728                                         pw_auto_step);
1729        }
1730
1731        basep->state = BASEP_SHOWN;
1732        basep_widget_update_winhints (basep);
1733
1734        gtk_signal_emit (GTK_OBJECT(basep),
1735                         basep_widget_signals[STATE_CHANGE_SIGNAL],
1736                         BASEP_SHOWN);
1737
1738        basep->enter_notify_timer_tag = 0;
1739        return FALSE;
1740}
1741
1742void
1743basep_widget_queue_autoshow (BasePWidget *basep)
1744{
1745        /* check if there's already a timeout set, and delete it if
1746         * there was */
1747        if (basep->state == BASEP_MOVING) {
1748#ifdef PANEL_DEBUG
1749                g_print ("return 2");
1750#endif
1751                return;
1752        }
1753
1754        if (basep->leave_notify_timer_tag != 0) {
1755                gtk_timeout_remove (basep->leave_notify_timer_tag);
1756                basep->leave_notify_timer_tag = 0;
1757        }
1758
1759        if (basep->enter_notify_timer_tag != 0) {
1760                gtk_timeout_remove (basep->enter_notify_timer_tag);
1761#ifdef PANEL_DEBUG
1762                g_print ("<timeout removed>\n");
1763#endif
1764        }
1765
1766        if ((basep->mode != BASEP_AUTO_HIDE) ||
1767            (basep->state == BASEP_SHOWN)) {
1768#ifdef PANEL_DEBUG
1769                g_print ("return 1\n");
1770#endif
1771                return;
1772        }
1773
1774        if (pw_minimize_delay == 0) {
1775                basep_widget_autoshow (basep);
1776        } else {
1777                /* set up our delay for popup. */
1778                basep->enter_notify_timer_tag =
1779                        gtk_timeout_add (pw_maximize_delay,
1780                                         basep_widget_autoshow, basep);
1781        }
1782}
1783
1784gboolean
1785basep_widget_autohide (gpointer data)
1786{
1787        static const char *supinfo[] = {"panel", "collapse", NULL};
1788        BasePWidget *basep = data;
1789
1790        g_return_val_if_fail (IS_BASEP_WIDGET(basep), TRUE);
1791
1792        if (basep->autohide_inhibit)
1793                return TRUE;
1794       
1795        if (basep->state == BASEP_MOVING) {
1796#ifdef PANEL_DEBUG
1797                g_warning ("autohide whilst moving");
1798#endif
1799                return TRUE;
1800        }
1801
1802        if ( (basep->state != BASEP_SHOWN) ||
1803             (basep->mode != BASEP_AUTO_HIDE) ||
1804             (panel_widget_is_cursor(PANEL_WIDGET(basep->panel), 0)) ) {
1805                return TRUE;
1806        }
1807       
1808        if (panel_applet_in_drag || basep->drawers_open>0)
1809                return TRUE;
1810
1811        if (!gdk_pointer_is_grabbed ()) {
1812                if (gdk_pointer_grab (GDK_ROOT_PARENT(), FALSE,
1813                                      0, NULL, NULL, GDK_CURRENT_TIME)
1814                    != GrabSuccess) {
1815                        return TRUE;
1816                } else {
1817                        gdk_pointer_ungrab (GDK_CURRENT_TIME);
1818                }
1819        }
1820
1821        gnome_triggers_vdo("", NULL, supinfo);
1822
1823        gtk_signal_emit(GTK_OBJECT(basep),
1824                        basep_widget_signals[STATE_CHANGE_SIGNAL],
1825                        BASEP_AUTO_HIDDEN);
1826
1827        /* if the app did any updating of the interface, flush that for us*/
1828        gdk_flush();
1829
1830        if (GTK_WIDGET_REALIZED(basep)) {
1831                BasePPosClass *klass = basep_widget_get_pos_class (basep);
1832                PanelOrientType hide_orient;
1833                int w, h, size;
1834
1835                basep->state = BASEP_AUTO_HIDDEN;
1836               
1837                hide_orient = klass->get_hide_orient (basep);
1838                basep_widget_get_size (basep, &w, &h);
1839                klass->get_hide_size (basep,
1840                                      hide_orient,
1841                                      &w, &h);
1842                size =  (hide_orient == ORIENT_UP ||
1843                         hide_orient == ORIENT_DOWN)
1844                        ? h : w;
1845
1846                basep->state = BASEP_MOVING;
1847                basep_widget_update_winhints (basep);
1848                basep_widget_do_hiding (basep,
1849                                        hide_orient,
1850                                        size,
1851                                        pw_auto_step);
1852        }
1853
1854
1855        basep->state = BASEP_AUTO_HIDDEN;
1856        basep_widget_update_winhints (basep);
1857
1858        basep->leave_notify_timer_tag = 0;
1859        return FALSE;
1860}
1861
1862void
1863basep_widget_queue_autohide(BasePWidget *basep)
1864{
1865        /* check if there's already a timeout set, and delete it if
1866         * there was */
1867        if (basep->state == BASEP_MOVING) {
1868#ifdef PANEL_DEBUG
1869                g_print ("return 2");
1870#endif
1871                return;
1872        }
1873
1874        if (basep->enter_notify_timer_tag != 0) {
1875                gtk_timeout_remove (basep->enter_notify_timer_tag);
1876                basep->enter_notify_timer_tag = 0;
1877        }
1878
1879        if (basep->leave_notify_timer_tag != 0) {
1880                gtk_timeout_remove (basep->leave_notify_timer_tag);
1881#ifdef PANEL_DEBUG
1882                g_print ("<timeout removed>\n");
1883#endif
1884        }
1885
1886        if ((basep->mode != BASEP_AUTO_HIDE) ||
1887            (basep->state != BASEP_SHOWN)) {
1888#ifdef PANEL_DEBUG
1889                g_print ("return 1\n");
1890#endif
1891                return;
1892        }
1893               
1894       /* set up our delay for popup. */
1895        basep->leave_notify_timer_tag =
1896                gtk_timeout_add (pw_minimize_delay,
1897                                 basep_widget_autohide, basep);
1898}
1899
1900void
1901basep_widget_get_menu_pos (BasePWidget *basep,
1902                           GtkWidget *menu,
1903                           int *x, int *y,
1904                           int wx, int wy,
1905                           int ww, int wh)
1906{
1907        GtkRequisition mreq;
1908        BasePPosClass *klass =
1909                basep_widget_get_pos_class (basep);
1910        g_return_if_fail (klass && klass->get_menu_pos);
1911
1912        gtk_widget_get_child_requisition(menu, &mreq);
1913
1914        klass->get_menu_pos (basep, menu, &mreq,
1915                             x, y, wx, wy,
1916                             ww, wh);
1917
1918        if (*x + mreq.width >
1919            multiscreen_x (basep->screen) + multiscreen_width (basep->screen))
1920                *x = multiscreen_x (basep->screen) +
1921                        multiscreen_width (basep->screen) - mreq.width;
1922        if (*x < multiscreen_x (basep->screen))
1923                *x = multiscreen_x (basep->screen);
1924
1925        if (*y + mreq.height >
1926            multiscreen_y (basep->screen) + multiscreen_height (basep->screen))
1927                *y = multiscreen_y (basep->screen) +
1928                        multiscreen_height (basep->screen) - mreq.height;
1929        if (*y < multiscreen_y (basep->screen))
1930                *y = multiscreen_y (basep->screen);
1931}
1932
1933PanelOrientType
1934basep_widget_get_applet_orient (BasePWidget *basep)
1935{
1936        BasePPosClass *klass =
1937                basep_widget_get_pos_class (basep);
1938
1939        g_return_val_if_fail (klass &&
1940                              klass->get_applet_orient, -1);
1941
1942        return klass->get_applet_orient(basep);
1943}
1944
1945#if 0
1946void
1947basep_widget_get_hide_size (BasePWidget *basep,
1948                            PanelOrientType hide_orient,
1949                            int *w, int *h)
1950{
1951        BasePPosClass *klass = basep_widget_get_pos_class(basep);
1952
1953        basep_widget_get_size(basep, w, h);
1954
1955        if (basep->state == BASEP_SHOWN) {
1956                g_warning ("get_hide_size() called on shown BasePWidget");
1957                return;
1958        }
1959       
1960        g_return_if_fail (klass && klass->get_hide_size);
1961        klass->get_hide_size (basep, hide_orient, w, h);
1962}
1963
1964void
1965basep_widget_get_hide_orient (BasePWidget *basep,
1966                              PanelOrientType *hide_orient)
1967{
1968        BasePPosClass *klass = basep_widget_get_pos_class(basep);
1969
1970        *hide_orient = -1;
1971        if (basep->state == BASEP_SHOWN) {
1972                g_warning ("get_hide_orient() called on shown BasePWidget");
1973                return;
1974        }
1975       
1976        g_return_if_fail (klass && klass->get_hide_size);
1977        klass->get_hide_orient (basep, hide_orient);
1978}
1979
1980void
1981basep_widget_get_hide_pos (BasePWidget *basep,
1982                           PanelOrientType hide_orient,
1983                           int *x, int *y)
1984{
1985        BasePPosClass *klass = basep_widget_get_pos_class(basep);
1986        int w, h;
1987
1988        if (basep->state == BASEP_SHOWN) {
1989                g_warning ("get_hide_pos() called on shown BasePWidget");
1990                return;
1991        }
1992       
1993        basep_widget_get_hide_size (basep, hide_orient, &w, &h);
1994        g_return_if_fail (klass && klass->get_hide_size);
1995        klass->get_hide_orient (basep, hide_orient);
1996}
1997#endif
1998
1999void
2000basep_widget_get_size (BasePWidget *basep,
2001                       int *w, int *h)
2002{
2003        GtkRequisition req;
2004        BasePPosClass *klass = basep_widget_get_pos_class (basep);
2005
2006        gtk_widget_size_request (basep->ebox, &req);
2007        *w = req.width;
2008        *h = req.height;
2009       
2010        g_return_if_fail (klass);
2011        if (klass->get_size)
2012                klass->get_size(basep, w, h);
2013}
2014
2015void
2016basep_widget_get_pos (BasePWidget *basep,
2017                      int *x, int *y)
2018{
2019        int w, h;
2020        BasePPosClass *klass =
2021                basep_widget_get_pos_class (basep);
2022
2023        g_return_if_fail (klass && klass->get_pos);
2024
2025        basep_widget_get_size (basep, &w, &h);
2026        klass->get_pos(basep, x, y, w, h);
2027}
2028
2029void
2030basep_widget_init_offsets (BasePWidget *basep)
2031{
2032        g_return_if_fail (basep != NULL);
2033        g_return_if_fail (IS_BASEP_WIDGET (basep));
2034
2035        if (GTK_WIDGET (basep)->window != NULL) {
2036                int x, y;
2037                gdk_window_get_pointer (GTK_WIDGET (basep)->window,
2038                                        &x, &y, NULL);
2039                basep->offset_x = x;
2040                basep->offset_y = y;
2041        } else {
2042                basep->offset_x = GTK_WIDGET (basep)->requisition.width / 2;
2043                basep->offset_y = GTK_WIDGET (basep)->requisition.height / 2;
2044        }
2045}
2046
2047void
2048basep_widget_set_pos (BasePWidget *basep,
2049                      int x, int y)
2050{
2051        int w, h;
2052        int newscreen;
2053        gboolean force = FALSE;
2054        BasePPosClass *klass =
2055                basep_widget_get_pos_class (basep);
2056
2057        g_return_if_fail (klass && klass->set_pos);
2058
2059        /* first take care of switching screens */
2060        newscreen = multiscreen_screen_from_pos (x, y);
2061        if (newscreen >= 0 &&
2062            newscreen != basep->screen) {
2063                force = TRUE;
2064                basep_widget_screen_change (basep, newscreen);
2065        }
2066
2067        basep_widget_get_size (basep, &w, &h);
2068        klass->set_pos (basep, x, y, w, h, force);
2069}
2070
2071void
2072basep_widget_pre_convert_hook (BasePWidget *basep)
2073{
2074        BasePPosClass  *klass = basep_widget_get_pos_class (basep);
2075        g_return_if_fail (klass && klass->pre_convert_hook);
2076
2077        klass->pre_convert_hook (basep);
2078}
2079
2080void
2081basep_widget_set_state (BasePWidget *basep, BasePState state,
2082                        gboolean emit)
2083{
2084        if (basep->state == state)
2085                return;
2086
2087        basep->state = state;
2088       
2089        if (emit)
2090                gtk_signal_emit(GTK_OBJECT(basep),
2091                                basep_widget_signals[STATE_CHANGE_SIGNAL],
2092                                state);
2093        panels_to_sync = TRUE;
2094}
2095
2096void
2097basep_widget_screen_change (BasePWidget *basep, int screen)
2098{
2099        g_return_if_fail (basep != NULL);
2100        g_return_if_fail (IS_BASEP_WIDGET (basep));
2101        g_return_if_fail (screen >= 0);
2102
2103        if (basep->screen == screen)
2104                return;
2105
2106        gtk_signal_emit (GTK_OBJECT (basep),
2107                         basep_widget_signals[SCREEN_CHANGE_SIGNAL],
2108                         screen);
2109}
2110
2111/*****
2112 * Collision avoidance stuff
2113 *****/
2114/* FIXME: needs to be per screen! */
2115typedef struct {
2116        int left;
2117        int center;
2118        int right;
2119} Border;
2120
2121typedef struct {
2122        int screen;
2123        Border borders[4];
2124        int left;
2125        int right;
2126        int top;
2127        int bottom;
2128} ScreenBorders;
2129
2130static GList *border_list = NULL;
2131
2132static ScreenBorders *
2133get_borders (int screen)
2134{
2135        GList *li;
2136        ScreenBorders *sb;
2137
2138        for (li = border_list; li != NULL; li = li->next) {
2139                sb = li->data;
2140                if (sb->screen == screen)
2141                        return sb;
2142        }
2143
2144        sb = g_new0 (ScreenBorders, 1);
2145        sb->screen = screen;
2146        border_list = g_list_prepend (border_list, sb);
2147
2148        return sb;
2149}
2150
2151static void
2152basep_calculate_borders (int screen)
2153{
2154        GSList *li;
2155        ScreenBorders *sb;
2156
2157        sb = get_borders (screen);
2158
2159        for (li = panel_list; li != NULL; li = li->next) {
2160                PanelData *pd = li->data;
2161                BasePWidget *basep;
2162                GtkRequisition chreq;
2163                BorderEdge edge;
2164
2165                g_assert (pd != NULL);
2166
2167                if ( ! IS_EDGE_WIDGET (pd->panel) &&
2168                     ! IS_ALIGNED_WIDGET (pd->panel))
2169                        continue;
2170
2171                basep = BASEP_WIDGET (pd->panel);
2172
2173                if (basep->mode == BASEP_AUTO_HIDE ||
2174                    basep->screen != screen)
2175                        continue;
2176
2177                gtk_widget_get_child_requisition (basep->ebox, &chreq);
2178
2179                edge = BORDER_POS (basep->pos)->edge;
2180
2181                if (IS_EDGE_WIDGET (basep)) {
2182                        BasePState state = basep->state;
2183                        if (PANEL_WIDGET (basep->panel)->orient ==
2184                            PANEL_VERTICAL) {
2185                                if (sb->borders[edge].left < chreq.width &&
2186                                    state != BASEP_HIDDEN_RIGHT)
2187                                        sb->borders[edge].left = chreq.width;
2188                                if (sb->borders[edge].center < chreq.width &&
2189                                    state != BASEP_HIDDEN_RIGHT &&
2190                                    state != BASEP_HIDDEN_LEFT)
2191                                        sb->borders[edge].center = chreq.width;
2192                                if (sb->borders[edge].right < chreq.width &&
2193                                    state != BASEP_HIDDEN_LEFT)
2194                                        sb->borders[edge].right = chreq.width;
2195                        } else {
2196                                if (sb->borders[edge].left < chreq.height &&
2197                                    state != BASEP_HIDDEN_RIGHT)
2198                                        sb->borders[edge].left = chreq.height;
2199                                if (sb->borders[edge].center < chreq.height &&
2200                                    state != BASEP_HIDDEN_RIGHT &&
2201                                    state != BASEP_HIDDEN_LEFT)
2202                                        sb->borders[edge].center = chreq.height;
2203                                if (sb->borders[edge].right < chreq.height &&
2204                                    state != BASEP_HIDDEN_LEFT)
2205                                        sb->borders[edge].right = chreq.height;
2206                        }
2207                } else /* ALIGNED */ {
2208                        AlignedAlignment align = ALIGNED_POS(basep->pos)->align;
2209                        if (PANEL_WIDGET (basep->panel)->orient ==
2210                            PANEL_VERTICAL) {
2211                                if (align == ALIGNED_LEFT &&
2212                                    sb->borders[edge].left < chreq.width)
2213                                        sb->borders[edge].left = chreq.width;
2214                                else if (align == ALIGNED_CENTER &&
2215                                         sb->borders[edge].center < chreq.width)
2216                                        sb->borders[edge].center = chreq.width;
2217                                else if (align == ALIGNED_RIGHT &&
2218                                         sb->borders[edge].right < chreq.width)
2219                                        sb->borders[edge].right = chreq.width;
2220                        } else {
2221                                if (align == ALIGNED_LEFT &&
2222                                    sb->borders[edge].left < chreq.height)
2223                                        sb->borders[edge].left = chreq.height;
2224                                else if (align == ALIGNED_CENTER &&
2225                                         sb->borders[edge].center < chreq.height)
2226                                        sb->borders[edge].center = chreq.height;
2227                                else if (align == ALIGNED_RIGHT &&
2228                                         sb->borders[edge].right < chreq.height)
2229                                        sb->borders[edge].right = chreq.height;
2230                        }
2231                }
2232        }
2233}
2234
2235static int
2236border_max (ScreenBorders *sb, BorderEdge edge)
2237{
2238        return MAX (sb->borders[edge].center,
2239                    MAX (sb->borders[edge].left, sb->borders[edge].right));
2240}
2241
2242void
2243basep_border_recalc (int screen)
2244{
2245        int i;
2246        GSList *li;
2247        ScreenBorders *sb;
2248        ScreenBorders old;
2249
2250        sb = get_borders (screen);
2251
2252        memcpy (&old, sb, sizeof (ScreenBorders));
2253
2254        for (i = 0; i < 4; i++) {
2255                sb->borders[i].left = 0;
2256                sb->borders[i].center = 0;
2257                sb->borders[i].right = 0;
2258        }
2259
2260        /* if not avoiding collisions, keeping things at 0 is a safe bet */
2261        if (global_config.avoid_collisions) {
2262                basep_calculate_borders (screen);
2263        }
2264
2265        sb->left = border_max (sb, BORDER_LEFT);
2266        sb->right = border_max (sb, BORDER_RIGHT);
2267        sb->top = border_max (sb, BORDER_TOP) +
2268                foobar_widget_get_height (screen);
2269        sb->bottom = border_max (sb, BORDER_BOTTOM);
2270
2271#ifdef PANEL_DEBUG
2272        g_print ("[basep_border_recalc] SCREEN %d (%d %d %d %d)\n", screen,
2273                 sb->left, sb->right, sb->top, sb->bottom);
2274#endif
2275
2276        if (memcmp (&old, sb, sizeof (ScreenBorders)) != 0) {
2277                for (li = panel_list; li != NULL; li = li->next) {
2278                        PanelData *pd = li->data;
2279                        GtkWidget *panel;
2280
2281                        g_assert (pd != NULL);
2282
2283                        panel = pd->panel;
2284
2285                        if (IS_BORDER_WIDGET (panel) &&
2286                            BASEP_WIDGET (panel)->screen == screen) {
2287                                gtk_widget_queue_resize (panel);
2288                        }
2289                }
2290
2291                if (sb->left != old.left ||
2292                    sb->right != old.right ||
2293                    sb->top != old.top ||
2294                    sb->bottom != old.bottom)
2295                        xstuff_setup_desktop_area (screen,
2296                                                   sb->left,
2297                                                   sb->right,
2298                                                   sb->top,
2299                                                   sb->bottom);
2300        }
2301}
2302
2303static guint queue_recalc_id = 0;
2304static GList *recalc_list = NULL;
2305
2306static gboolean
2307queue_recalc_handler (gpointer data)
2308{
2309        GList *list, *li;
2310
2311        queue_recalc_id = 0;
2312
2313        list = recalc_list;
2314        recalc_list = NULL;
2315
2316        for (li = list; li != NULL; li = li->next) {
2317                int screen = GPOINTER_TO_INT (li->data);
2318                basep_border_recalc (screen);
2319        }
2320
2321        g_list_free (list);
2322
2323        return FALSE;
2324}
2325
2326void
2327basep_border_queue_recalc (int screen)
2328{
2329        if (g_list_find (recalc_list,
2330                         GINT_TO_POINTER (screen)) == NULL)
2331                recalc_list = g_list_prepend (recalc_list,
2332                                              GINT_TO_POINTER (screen));
2333        if (queue_recalc_id == 0) {
2334                queue_recalc_id = gtk_idle_add (queue_recalc_handler, NULL);
2335        }
2336}
2337
2338void
2339basep_border_get (int screen, BorderEdge edge,
2340                  int *left, int *center, int *right)
2341{
2342        ScreenBorders *sb;
2343
2344        g_assert (screen >=0);
2345        g_assert (edge >=0 && edge <= 3);
2346
2347        sb = get_borders (screen);
2348
2349        if (left != NULL)
2350                *left = sb->borders[edge].left;
2351        if (center != NULL)
2352                *center = sb->borders[edge].center;
2353        if (right != NULL)
2354                *right = sb->borders[edge].right;
2355}
Note: See TracBrowser for help on using the repository browser.