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

Revision 17152, 74.1 KB checked in by ghudson, 23 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r17151, which included commits to RCS files with non-trunk default branches.
Line 
1/* Gnome panel: panel widget
2 * (C) 1997,1998,1999,2000 the Free Software Foundation
3 * (C) 2000 Eazel, Inc.
4 *
5 * Authors:  George Lebl
6 */
7#include <limits.h>
8#include <math.h>
9#include <config.h>
10#include <gtk/gtk.h>
11#include <gnome.h>
12#include "panel-widget.h"
13#include "button-widget.h"
14#include "panel-util.h"
15#include <gdk-pixbuf/gdk-pixbuf.h>
16#include <libart_lgpl/art_misc.h>
17#include <libart_lgpl/art_affine.h>
18#include <libart_lgpl/art_filterlevel.h>
19#include "rgb-stuff.h"
20#include <gdk/gdkx.h>
21#include <X11/Xatom.h>
22
23GSList *panels = NULL; /*other panels we might want to move the applet to*/
24
25/*define for some debug output*/
26/*#define PANEL_DEBUG 1*/
27
28#define TRANSLUCENT_OPACITY 128
29
30/*there  can universally be only one applet being dragged since we assume
31we only have one mouse :) */
32gboolean panel_applet_in_drag = FALSE;
33
34/* Commie mode! */
35extern gboolean commie_mode;
36
37static void panel_widget_class_init     (PanelWidgetClass *klass);
38static void panel_widget_init           (PanelWidget      *panel_widget);
39static int  panel_try_to_set_pixmap     (PanelWidget      *panel,
40                                         char             *pixmap);
41static void panel_resize_pixmap         (PanelWidget      *panel);
42static void panel_try_to_set_back_color (PanelWidget      *panel,
43                                         GdkColor         *color);
44static void panel_widget_size_request   (GtkWidget        *widget,
45                                         GtkRequisition   *requisition);
46static void panel_widget_size_allocate  (GtkWidget        *widget,
47                                         GtkAllocation    *allocation);
48static void panel_widget_cadd           (GtkContainer     *container,
49                                         GtkWidget        *widget);
50static void panel_widget_cremove        (GtkContainer     *container,
51                                         GtkWidget        *widget);
52static int  panel_widget_expose         (GtkWidget        *widget,
53                                         GdkEventExpose   *event);
54static void panel_widget_draw           (GtkWidget        *widget,
55                                         GdkRectangle     *area);
56static void applet_move                 (PanelWidget      *panel,
57                                         GtkWidget        *applet);
58
59
60/*global settings*/
61int pw_explicit_step = 50;
62int pw_drawer_step = 20;
63int pw_auto_step = 10;
64int pw_minimized_size = 6;
65int pw_minimize_delay = 300;
66int pw_maximize_delay = 0;
67gboolean pw_disable_animations = FALSE;
68PanelMovementType pw_movement_type = PANEL_SWITCH_MOVE;
69int pw_applet_padding = 3;
70int pw_applet_border_padding = 0;
71
72/* translucent panel variables */
73GdkPixmap *desktop_pixmap = NULL;
74
75#define APPLET_EVENT_MASK (GDK_BUTTON_PRESS_MASK |              \
76                           GDK_BUTTON_RELEASE_MASK |            \
77                           GDK_POINTER_MOTION_MASK |            \
78                           GDK_POINTER_MOTION_HINT_MASK)
79
80typedef void (*BackSignal) (GtkObject * object,
81                            PanelBackType type,
82                            char *pixmap,
83                            GdkColor *color,
84                            gpointer data);
85
86/************************
87 debugging
88 ************************/
89/*static void
90debug_dump_panel_list(PanelWidget *panel)
91{
92        GList *list;
93        puts("\nDUMP START\n");
94        for(list = panel->applet_list;list!=NULL;list=g_list_next(list)) {
95                AppletData *ad = list->data;
96                printf("pos: %d cells: %d\n",ad->pos,ad->cells);
97        }
98        puts("\nDUMP END\n");
99}*/
100
101/************************
102 convenience functions
103 ************************/
104static int
105applet_data_compare (AppletData *ad1, AppletData *ad2)
106{
107        return ad1->pos - ad2->pos;
108}
109
110/************************
111 widget core
112 ************************/
113
114guint
115panel_widget_get_type (void)
116{
117        static guint panel_widget_type = 0;
118
119        if (!panel_widget_type) {
120                GtkTypeInfo panel_widget_info = {
121                        "PanelWidget",
122                        sizeof (PanelWidget),
123                        sizeof (PanelWidgetClass),
124                        (GtkClassInitFunc) panel_widget_class_init,
125                        (GtkObjectInitFunc) panel_widget_init,
126                        (GtkArgSetFunc) NULL,
127                        (GtkArgGetFunc) NULL,
128                };
129
130                panel_widget_type =
131                        gtk_type_unique (gtk_fixed_get_type (),
132                                         &panel_widget_info);
133        }
134
135        return panel_widget_type;
136}
137
138enum {
139        ORIENT_CHANGE_SIGNAL,
140        SIZE_CHANGE_SIGNAL,
141        APPLET_MOVE_SIGNAL,
142        APPLET_ADDED_SIGNAL,
143        APPLET_REMOVED_SIGNAL,
144        BACK_CHANGE_SIGNAL,
145        APPLET_DRAW_SIGNAL,
146        APPLET_ABOUT_TO_DIE_SIGNAL,
147        LAST_SIGNAL
148};
149
150static guint panel_widget_signals[LAST_SIGNAL] = {0};
151static GtkFixedClass *parent_class = NULL;
152
153
154static void
155marshal_signal_back (GtkObject * object,
156                     GtkSignalFunc func,
157                     gpointer func_data,
158                     GtkArg * args)
159{
160        BackSignal rfunc;
161
162        rfunc = (BackSignal) func;
163
164        (*rfunc) (object, GTK_VALUE_ENUM (args[0]),
165                  GTK_VALUE_POINTER (args[1]),
166                  GTK_VALUE_POINTER (args[2]),
167                  func_data);
168}
169
170static void
171panel_widget_class_init (PanelWidgetClass *class)
172{
173        GtkObjectClass *object_class = (GtkObjectClass*) class;
174        GtkWidgetClass *widget_class = (GtkWidgetClass*) class;
175        GtkContainerClass *container_class = (GtkContainerClass*) class;
176       
177        parent_class = gtk_type_class (gtk_fixed_get_type ());
178
179        panel_widget_signals[ORIENT_CHANGE_SIGNAL] =
180                gtk_signal_new("orient_change",
181                               GTK_RUN_LAST,
182                               object_class->type,
183                               GTK_SIGNAL_OFFSET(PanelWidgetClass,
184                                                 orient_change),
185                               gtk_marshal_NONE__ENUM,
186                               GTK_TYPE_NONE,
187                               1,
188                               GTK_TYPE_ENUM);
189        panel_widget_signals[SIZE_CHANGE_SIGNAL] =
190                gtk_signal_new("size_change",
191                               GTK_RUN_LAST,
192                               object_class->type,
193                               GTK_SIGNAL_OFFSET(PanelWidgetClass,
194                                                 size_change),
195                               gtk_marshal_NONE__INT,
196                               GTK_TYPE_NONE,
197                               1,
198                               GTK_TYPE_INT);
199        panel_widget_signals[APPLET_MOVE_SIGNAL] =
200                gtk_signal_new("applet_move",
201                               GTK_RUN_LAST,
202                               object_class->type,
203                               GTK_SIGNAL_OFFSET(PanelWidgetClass,
204                                                 applet_move),
205                               gtk_marshal_NONE__POINTER,
206                               GTK_TYPE_NONE,
207                               1,
208                               GTK_TYPE_POINTER);
209        panel_widget_signals[APPLET_ADDED_SIGNAL] =
210                gtk_signal_new("applet_added",
211                               GTK_RUN_LAST,
212                               object_class->type,
213                               GTK_SIGNAL_OFFSET(PanelWidgetClass,
214                                                 applet_added),
215                               gtk_marshal_NONE__POINTER,
216                               GTK_TYPE_NONE,
217                               1,
218                               GTK_TYPE_POINTER);
219        panel_widget_signals[APPLET_REMOVED_SIGNAL] =
220                gtk_signal_new("applet_removed",
221                               GTK_RUN_LAST,
222                               object_class->type,
223                               GTK_SIGNAL_OFFSET(PanelWidgetClass,
224                                                 applet_removed),
225                               gtk_marshal_NONE__POINTER,
226                               GTK_TYPE_NONE,
227                               1,
228                               GTK_TYPE_POINTER);
229        panel_widget_signals[BACK_CHANGE_SIGNAL] =
230                gtk_signal_new("back_change",
231                               GTK_RUN_LAST,
232                               object_class->type,
233                               GTK_SIGNAL_OFFSET(PanelWidgetClass,
234                                                 back_change),
235                               marshal_signal_back,
236                               GTK_TYPE_NONE,
237                               3,
238                               GTK_TYPE_ENUM,
239                               GTK_TYPE_POINTER,
240                               GTK_TYPE_POINTER);
241        panel_widget_signals[APPLET_DRAW_SIGNAL] =
242                gtk_signal_new("applet_draw",
243                               GTK_RUN_LAST,
244                               object_class->type,
245                               GTK_SIGNAL_OFFSET(PanelWidgetClass,
246                                                 applet_draw),
247                               gtk_marshal_NONE__POINTER,
248                               GTK_TYPE_NONE,
249                               1,
250                               GTK_TYPE_POINTER);
251        panel_widget_signals[APPLET_ABOUT_TO_DIE_SIGNAL] =
252                gtk_signal_new("applet_about_to_die",
253                               GTK_RUN_LAST,
254                               object_class->type,
255                               GTK_SIGNAL_OFFSET(PanelWidgetClass,
256                                                 applet_about_to_die),
257                               gtk_marshal_NONE__POINTER,
258                               GTK_TYPE_NONE,
259                               1,
260                               GTK_TYPE_POINTER);
261        gtk_object_class_add_signals(object_class,panel_widget_signals,
262                                     LAST_SIGNAL);
263
264        class->orient_change = NULL;
265        class->size_change = NULL;
266        class->applet_move = applet_move;
267        class->applet_added = NULL;
268        class->applet_removed = NULL;
269        class->back_change = NULL;
270        class->applet_draw = NULL;
271        class->applet_about_to_die = NULL;
272       
273        widget_class->size_request = panel_widget_size_request;
274        widget_class->size_allocate = panel_widget_size_allocate;
275        widget_class->expose_event = panel_widget_expose;
276        widget_class->draw = panel_widget_draw;
277
278        container_class->add = panel_widget_cadd;
279        container_class->remove = panel_widget_cremove;
280}
281
282static void
283applet_move(PanelWidget *panel, GtkWidget *applet)
284{
285        if(panel->back_type == PANEL_BACK_COLOR ||
286           (panel->back_type == PANEL_BACK_NONE &&
287            !GTK_WIDGET(panel)->style->bg_pixmap[GTK_WIDGET_STATE(panel)]))
288                return;
289        if(IS_BUTTON_WIDGET(applet)) {
290                ButtonWidget *button = BUTTON_WIDGET(applet);
291                if(!button->no_alpha && button->cache) {
292                        gdk_pixmap_unref(button->cache);
293                        button->cache = NULL;
294                }
295        }
296        gtk_signal_emit(GTK_OBJECT(panel),
297                        panel_widget_signals[APPLET_DRAW_SIGNAL],
298                        applet);
299}
300
301static void
302remove_panel_from_forbidden(PanelWidget *panel, PanelWidget *r)
303{
304        GSList *list;
305        GtkWidget *parent_panel;
306       
307        g_return_if_fail(panel!=NULL);
308        g_return_if_fail(IS_PANEL_WIDGET(panel));
309        g_return_if_fail(r!=NULL);
310        g_return_if_fail(IS_PANEL_WIDGET(r));
311
312        if(!panel->master_widget)
313                return;
314
315        list = gtk_object_get_data(GTK_OBJECT(panel->master_widget),
316                                   PANEL_APPLET_FORBIDDEN_PANELS);
317        if(list) {
318                list = g_slist_remove(list,r);
319                gtk_object_set_data(GTK_OBJECT(panel->master_widget),
320                                    PANEL_APPLET_FORBIDDEN_PANELS,
321                                    list);
322        }
323        parent_panel = panel->master_widget->parent;
324        if (parent_panel)
325                remove_panel_from_forbidden(PANEL_WIDGET(parent_panel), r);
326}
327
328static void
329add_panel_to_forbidden(PanelWidget *panel, PanelWidget *r)
330{
331        GSList *list;
332        GtkWidget *parent_panel;
333
334        g_return_if_fail(panel!=NULL);
335        g_return_if_fail(IS_PANEL_WIDGET(panel));
336        g_return_if_fail(r!=NULL);
337        g_return_if_fail(IS_PANEL_WIDGET(r));
338
339        if(!panel->master_widget)
340                return;
341
342        list = gtk_object_get_data(GTK_OBJECT(panel->master_widget),
343                                   PANEL_APPLET_FORBIDDEN_PANELS);
344        if(g_slist_find(list,r)==NULL) {
345                list = g_slist_prepend(list,r);
346
347                gtk_object_set_data(GTK_OBJECT(panel->master_widget),
348                                    PANEL_APPLET_FORBIDDEN_PANELS,
349                                    list);
350        }
351        parent_panel = panel->master_widget->parent;
352        if (parent_panel)
353                add_panel_to_forbidden(PANEL_WIDGET(parent_panel), r);
354}
355
356static void
357run_up_forbidden(PanelWidget *panel,
358                 void (*runfunc)(PanelWidget *,PanelWidget *))
359{
360        GList *list;
361
362        g_return_if_fail(panel!=NULL);
363        g_return_if_fail(IS_PANEL_WIDGET(panel));
364
365        for(list = panel->applet_list;list!=NULL;list = g_list_next(list)) {
366                AppletData *ad = list->data;
367                PanelWidget *p =
368                        gtk_object_get_data(GTK_OBJECT(ad->applet),
369                                            PANEL_APPLET_ASSOC_PANEL_KEY);
370                if(p)
371                        run_up_forbidden(p,runfunc);
372        }
373        (*runfunc)(panel,panel);
374}
375
376
377static void
378panel_widget_cadd(GtkContainer *container, GtkWidget *widget)
379{
380        PanelWidget *p;
381
382        g_return_if_fail (container != NULL);
383        g_return_if_fail (IS_PANEL_WIDGET (container));
384        g_return_if_fail (widget != NULL);
385        g_return_if_fail (GTK_IS_WIDGET (widget));
386
387        panel_widget_add(PANEL_WIDGET(container),widget,0);
388        p = gtk_object_get_data(GTK_OBJECT(widget),
389                                PANEL_APPLET_ASSOC_PANEL_KEY);
390        if(p)
391                run_up_forbidden(p,add_panel_to_forbidden);
392}
393
394static void
395panel_widget_cremove (GtkContainer *container, GtkWidget *widget)
396{
397        AppletData *ad;
398        PanelWidget *p;
399        PanelWidget *panel;
400
401        g_return_if_fail (container != NULL);
402        g_return_if_fail (IS_PANEL_WIDGET (container));
403        g_return_if_fail (widget != NULL);
404        g_return_if_fail (GTK_IS_WIDGET (widget));
405       
406        panel = PANEL_WIDGET (container);
407       
408        ad = gtk_object_get_data (GTK_OBJECT (widget), PANEL_APPLET_DATA);
409        p = gtk_object_get_data (GTK_OBJECT (widget),
410                                 PANEL_APPLET_ASSOC_PANEL_KEY);
411
412        if (ad != NULL &&
413            ad->no_die == 0) {
414                gtk_signal_emit (GTK_OBJECT (container),
415                                 panel_widget_signals[APPLET_ABOUT_TO_DIE_SIGNAL],
416                                 widget);
417        }
418
419
420        if (p != NULL)
421                run_up_forbidden (p, remove_panel_from_forbidden);
422
423        if(panel->currently_dragged_applet == ad)
424                panel_widget_applet_drag_end(panel);
425
426        gtk_widget_ref(widget);
427        if (GTK_CONTAINER_CLASS (parent_class)->remove)
428                (* GTK_CONTAINER_CLASS (parent_class)->remove) (container,
429                                                                widget);
430        if (ad != NULL) {
431                PanelWidget *panel = PANEL_WIDGET (container);
432
433                panel->applet_list = g_list_remove (panel->applet_list, ad);
434                panel->no_window_applet_list =
435                        g_list_remove (panel->no_window_applet_list, ad);
436        }
437
438        gtk_signal_emit (GTK_OBJECT (container),
439                         panel_widget_signals[APPLET_REMOVED_SIGNAL],
440                         widget);
441        gtk_widget_unref(widget);
442}
443
444
445/*get the number of applets*/
446int
447panel_widget_get_applet_count(PanelWidget *panel)
448{
449        g_return_val_if_fail(panel!=NULL,-1);
450        g_return_val_if_fail(IS_PANEL_WIDGET(panel),-1);
451
452        return g_list_length(GTK_FIXED(panel)->children);
453}
454
455/*get the list item of the data on the position pos*/
456static GList *
457get_applet_list_pos(PanelWidget *panel, int pos)
458{
459        GList *list;
460
461        g_return_val_if_fail(panel!=NULL,NULL);
462        g_return_val_if_fail(IS_PANEL_WIDGET(panel),NULL);
463       
464        for(list=panel->applet_list;list!=NULL;list=g_list_next(list)) {
465                AppletData *ad = list->data;
466                if(ad->pos <= pos) {
467                       if(ad->pos+ad->cells > pos)
468                               return list;
469                } else
470                        return NULL;
471        }
472        return NULL;
473}
474
475/*tells us if an applet is "stuck" on the right side*/
476int
477panel_widget_is_applet_stuck(PanelWidget *panel, GtkWidget *applet)
478{
479        AppletData *ad;
480        GList *list;
481        int i;
482
483        g_return_val_if_fail(panel!=NULL,FALSE);
484        g_return_val_if_fail(IS_PANEL_WIDGET(panel),FALSE);
485        g_return_val_if_fail(applet!=NULL,FALSE);
486        g_return_val_if_fail(GTK_IS_WIDGET(applet),FALSE);
487
488        ad = gtk_object_get_data(GTK_OBJECT(applet), PANEL_APPLET_DATA);
489
490        g_return_val_if_fail(ad!=NULL,FALSE);
491
492        list = g_list_find(panel->applet_list,ad);
493
494        g_return_val_if_fail(list!=NULL,FALSE);
495       
496        do {
497                i=ad->pos+ad->cells;
498                if(i==panel->size)
499                        return TRUE;
500                list = g_list_next(list);
501                if(!list)
502                        break;
503                ad = list->data;
504        } while(ad->pos==i);
505        return FALSE;
506}
507
508static int
509allocate_dirty_child(gpointer data)
510{
511        AppletData *ad = data;
512        PanelWidget *panel;
513        GtkAllocation challoc;
514        GtkRequisition chreq;
515       
516        g_return_val_if_fail(ad != NULL,FALSE);
517        g_return_val_if_fail(ad->applet != NULL,FALSE);
518        g_return_val_if_fail(ad->applet->parent != NULL,FALSE);
519        g_return_val_if_fail(IS_PANEL_WIDGET(ad->applet->parent),FALSE);
520
521        panel = PANEL_WIDGET(ad->applet->parent);
522       
523        if(!ad->dirty)
524                return FALSE;
525       
526        gtk_widget_get_child_requisition(ad->applet,&chreq);
527
528        if(panel->orient == PANEL_HORIZONTAL) {
529                ad->cells = chreq.width + pw_applet_padding;
530                challoc.x = ad->pos;
531                challoc.y = (GTK_WIDGET(panel)->allocation.height -
532                             chreq.height) / 2;
533        } else {
534                ad->cells = chreq.height + pw_applet_padding;
535                challoc.x = (GTK_WIDGET(panel)->allocation.width -
536                             chreq.width) / 2;
537                challoc.y = ad->pos;
538        }
539        challoc.width = chreq.width;
540        challoc.height = chreq.height;
541        gtk_widget_size_allocate(ad->applet,&challoc);
542
543        gtk_signal_emit(GTK_OBJECT(panel),
544                        panel_widget_signals[APPLET_MOVE_SIGNAL],
545                        ad->applet);
546
547        return FALSE;
548}
549
550static void
551panel_widget_queue_applet_for_resize(AppletData *ad)
552{
553        ad->dirty = TRUE;
554        g_idle_add(allocate_dirty_child,ad);
555}
556
557
558static void
559panel_widget_switch_applet_right(PanelWidget *panel, GList *list)
560{
561        AppletData *ad;
562        AppletData *nad = NULL;
563
564        g_return_if_fail(panel!=NULL);
565        g_return_if_fail(IS_PANEL_WIDGET(panel));
566        g_return_if_fail(list!=NULL);
567       
568        ad = list->data;
569
570        if(list->next)
571                nad = list->next->data;
572        if(!nad || nad->pos > ad->pos+ad->cells) {
573                ad->pos++;
574                panel_widget_queue_applet_for_resize(ad);
575                return;
576        }
577
578        nad->pos = ad->pos;
579        ad->pos = nad->pos+nad->cells;
580        panel->applet_list = my_g_list_swap_next(panel->applet_list,list);
581
582        panel_widget_queue_applet_for_resize(ad);
583        panel_widget_queue_applet_for_resize(nad);
584}
585
586static void
587panel_widget_switch_applet_left(PanelWidget *panel, GList *list)
588{
589        AppletData *ad;
590        AppletData *pad = NULL;
591
592        g_return_if_fail(panel!=NULL);
593        g_return_if_fail(IS_PANEL_WIDGET(panel));
594        g_return_if_fail(list!=NULL);
595       
596        ad = list->data;
597
598        if(list->prev)
599                pad = list->prev->data;
600        if(!pad || pad->pos+pad->cells < ad->pos) {
601                ad->pos--;
602                panel_widget_queue_applet_for_resize(ad);
603                return;
604        }
605        ad->pos = pad->pos;
606        pad->pos = ad->pos+ad->cells;
607        panel->applet_list = my_g_list_swap_prev(panel->applet_list,list);
608
609        panel_widget_queue_applet_for_resize(ad);
610        panel_widget_queue_applet_for_resize(pad);
611}
612
613static int
614panel_widget_get_right_switch_pos(PanelWidget *panel, GList *list)
615{
616        AppletData *ad;
617        AppletData *nad = NULL;
618
619        g_return_val_if_fail(panel!=NULL,-1);
620        g_return_val_if_fail(IS_PANEL_WIDGET(panel),-1);
621        g_return_val_if_fail(list!=NULL,-1);
622       
623        ad = list->data;
624
625        if(list->next)
626                nad = list->next->data;
627        if(!nad || nad->pos > ad->pos+ad->cells)
628                return ad->pos+1;
629        return nad->pos+nad->cells-ad->cells;
630}
631
632static int
633panel_widget_get_left_switch_pos(PanelWidget *panel, GList *list)
634{
635        AppletData *ad;
636        AppletData *pad = NULL;
637
638        g_return_val_if_fail(panel!=NULL,-1);
639        g_return_val_if_fail(IS_PANEL_WIDGET(panel),-1);
640        g_return_val_if_fail(list!=NULL,-1);
641       
642        ad = list->data;
643
644        if(list->prev)
645                pad = list->prev->data;
646        if(!pad || pad->pos+pad->cells < ad->pos)
647                return ad->pos-1;
648        return pad->pos;
649}
650
651
652static void
653panel_widget_switch_move (PanelWidget *panel, AppletData *ad, int moveby)
654{
655        int padding;
656        int finalpos;
657        int pos;
658        GList *list;
659
660        g_return_if_fail (ad != NULL);
661        g_return_if_fail (panel != NULL);
662        g_return_if_fail (IS_PANEL_WIDGET (panel));
663
664        if (moveby == 0)
665                return;
666
667        list = g_list_find (panel->applet_list, ad);
668        g_return_if_fail (list != NULL);
669
670        finalpos = ad->pos + moveby;
671
672        if (panel->no_padding_on_ends)
673                padding = 0;
674        else
675                padding = pw_applet_padding;
676
677        if (ad->pos < finalpos) {
678                while (ad->pos < finalpos) {
679                        pos = panel_widget_get_right_switch_pos (panel, list);
680                        if (pos + ad->cells > panel->size ||
681                            abs (pos - finalpos) > abs (ad->pos - finalpos))
682                                return;
683                        panel_widget_switch_applet_right (panel, list);
684                }
685        } else {
686                while (ad->pos > finalpos) {
687                        pos = panel_widget_get_left_switch_pos (panel, list);
688                        if (pos < padding ||
689                            abs (pos - finalpos) > abs (ad->pos - finalpos))
690                                return;
691                        panel_widget_switch_applet_left (panel, list);
692                }
693        }
694}
695
696static int
697push_applet_right(PanelWidget *panel, GList *list)
698{
699        AppletData *ad = NULL;
700        AppletData *nad = NULL;
701
702        g_return_val_if_fail(panel!=NULL,FALSE);
703        g_return_val_if_fail(IS_PANEL_WIDGET(panel),FALSE);
704       
705        if (list) {
706                ad = list->data;
707       
708                if(ad->pos + ad->cells >= panel->size)
709                        return FALSE;
710
711                if(list->next)
712                        nad = list->next->data;
713        }
714
715        if(!nad || nad->pos > ad->pos+ad->cells) {
716                ad->pos++;
717                panel_widget_queue_applet_for_resize(ad);
718                return TRUE;
719        }
720
721        g_return_val_if_fail(list!=NULL,FALSE);
722       
723        if(!push_applet_right(panel,list->next)) {
724                return FALSE;
725        }
726        ad->pos++;
727        panel_widget_queue_applet_for_resize(ad);
728        return TRUE;
729}
730
731static int
732push_applet_left(PanelWidget *panel, GList *list)
733{
734        AppletData *ad = NULL;
735        AppletData *pad = NULL;
736
737        g_return_val_if_fail(panel!=NULL,FALSE);
738        g_return_val_if_fail(IS_PANEL_WIDGET(panel),FALSE);
739
740        if (list) {
741                ad = list->data;
742
743                if(ad->pos <= (panel->no_padding_on_ends?0:pw_applet_padding))
744                        return FALSE;
745
746                if(list->prev)
747                        pad = list->prev->data;
748        }
749
750        if(!list || !pad || pad->pos+pad->cells < ad->pos) {
751                ad->pos--;
752                panel_widget_queue_applet_for_resize(ad);
753                return TRUE;
754        }
755
756        g_return_val_if_fail(list!=NULL,FALSE);
757       
758        if(!push_applet_left(panel,list->prev)) {
759                return FALSE;
760        }
761        ad->pos--;
762        panel_widget_queue_applet_for_resize(ad);
763        return TRUE;
764}
765
766static void
767panel_widget_push_move (PanelWidget *panel, AppletData *ad, int moveby)
768{
769        int finalpos;
770        GList *list;
771
772        g_return_if_fail (ad != NULL);
773        g_return_if_fail (panel != NULL);
774        g_return_if_fail (IS_PANEL_WIDGET (panel));
775
776        if (moveby == 0)
777                return;
778
779        list = g_list_find (panel->applet_list, ad);
780        g_return_if_fail (list != NULL);
781       
782        finalpos = ad->pos + moveby;
783
784        if (ad->pos < finalpos) {
785                while (ad->pos < finalpos) {
786                        if ( ! push_applet_right (panel, list))
787                                return;
788                }
789        } else {
790                while (ad->pos > finalpos) {
791                        if ( ! push_applet_left (panel, list))
792                                return;
793                }
794        }
795}
796
797/*this is a special function and may fail if called improperly, it works
798only under special circumstance when we know there is nothing from
799old_size to panel->size*/
800static void
801panel_widget_right_stick(PanelWidget *panel,int old_size)
802{
803        int i,pos;
804        GList *list,*prev;
805        AppletData *ad;
806
807        g_return_if_fail(panel!=NULL);
808        g_return_if_fail(IS_PANEL_WIDGET(panel));
809        g_return_if_fail(old_size>=0);
810       
811        if(old_size>=panel->size ||
812           panel->packed)
813                return;
814       
815        list = get_applet_list_pos(panel,old_size-1);
816
817        if(!list)
818                return;
819       
820        pos = panel->size-1;
821
822        ad = list->data;
823        do {
824                i = ad->pos;
825                ad->pos = pos--;
826                ad->cells = 1;
827                prev = list;
828                list = g_list_previous(list);
829                if(!list)
830                        break;
831                ad = list->data;
832        } while(ad->pos+ad->cells == i);
833
834        for(list = prev;list!=NULL;list=g_list_next(list))
835                gtk_signal_emit(GTK_OBJECT(panel),
836                                panel_widget_signals[APPLET_MOVE_SIGNAL],
837                                ((AppletData *)list->data)->applet);
838}
839
840static void
841panel_widget_size_request(GtkWidget *widget, GtkRequisition *requisition)
842{
843        PanelWidget *panel;
844        GList *list;
845
846        g_return_if_fail(widget!=NULL);
847        g_return_if_fail(IS_PANEL_WIDGET(widget));
848        g_return_if_fail(requisition!=NULL);
849
850        panel = PANEL_WIDGET(widget);
851
852        if(panel->orient == PANEL_HORIZONTAL) {
853                requisition->width = pw_applet_padding;
854                requisition->height = panel->sz;
855        } else {
856                requisition->height = pw_applet_padding;
857                requisition->width = panel->sz;
858        }
859
860        for(list = panel->applet_list; list!=NULL; list = g_list_next(list)) {
861                AppletData *ad = list->data;
862                GtkRequisition chreq;
863                gtk_widget_size_request(ad->applet,&chreq);
864                if(panel->orient == PANEL_HORIZONTAL) {
865                        if(requisition->height - 2*pw_applet_border_padding < chreq.height)
866                                requisition->height = chreq.height + 2*pw_applet_border_padding;
867                        if(panel->packed)
868                                requisition->width += chreq.width +
869                                        pw_applet_padding;
870                } else {
871                        if(requisition->width - 2*pw_applet_border_padding < chreq.width)
872                                requisition->width = chreq.width + 2*pw_applet_border_padding;
873                        if(panel->packed)
874                                requisition->height += chreq.height +
875                                        pw_applet_padding;
876                }
877        }
878        if(!panel->packed) {
879                if(panel->orient == PANEL_HORIZONTAL) {
880                        requisition->width = panel->size;
881                } else {
882                        requisition->height = panel->size;
883                }
884        } else if(/*panel->packed &&*/ panel->no_padding_on_ends) {
885                if(panel->orient == PANEL_HORIZONTAL) {
886                        requisition->width -= pw_applet_padding*2;
887                } else {
888                        requisition->height -= pw_applet_padding*2;
889                }
890        }
891        requisition->width = CLAMP (requisition->width, 12, gdk_screen_width ());
892        requisition->height = CLAMP (requisition->height, 12, gdk_screen_height ());
893}
894
895static void
896make_background(PanelWidget *panel, guchar *rgb_buf,
897                int x, int y, int w, int h,
898                GdkPixbuf *pb, int scale_w, int scale_h,
899                int rotate)
900{
901        if(pb) {
902                if(scale_w == 0 || scale_h == 0) {
903                        tile_rgb(rgb_buf,w,h,x,y,w*3,
904                                 gdk_pixbuf_get_pixels(pb),
905                                 gdk_pixbuf_get_width(pb),
906                                 gdk_pixbuf_get_height(pb),
907                                 gdk_pixbuf_get_rowstride(pb),
908                                 gdk_pixbuf_get_has_alpha(pb));
909                } else {
910                        tile_rgb_pixbuf(rgb_buf, w, h, x, y, w*3,
911                                        pb, scale_w, scale_h,
912                                        rotate);
913                }
914        } else {
915                int i;
916                int size;
917                int r,g,b;
918                guchar *p;
919                if(panel->back_type != PANEL_BACK_COLOR) {
920                        GtkWidget *widget = GTK_WIDGET(panel);
921                        /* convert to 8 bit per channel */
922                        r = widget->style->bg[GTK_WIDGET_STATE(widget)].red>>8;
923                        g = widget->style->bg[GTK_WIDGET_STATE(widget)].green>>8;
924                        b = widget->style->bg[GTK_WIDGET_STATE(widget)].blue>>8;
925                } else {
926                        /* convert to 8 bit per channel */
927                        r = panel->back_color.red>>8;
928                        g = panel->back_color.green>>8;
929                        b = panel->back_color.blue>>8;
930                }
931                size = w*h;
932                p = rgb_buf;
933                for(i=0;i<size;i++) {
934                        (*p++) = r;
935                        (*p++) = g;
936                        (*p++) = b;
937                }
938        }
939}
940
941static void
942send_draw_to_all_applets(PanelWidget *panel)
943{
944        GList *li;
945        for(li = panel->applet_list; li != NULL;
946            li = g_list_next(li)) {
947                AppletData *ad = li->data;
948                gtk_signal_emit(GTK_OBJECT(panel),
949                                panel_widget_signals[APPLET_DRAW_SIGNAL],
950                                ad->applet);
951        }
952}
953
954static void
955kill_cache_on_all_buttons(PanelWidget *panel, gboolean even_no_alpha)
956{
957        GList *li;
958        for(li = panel->applet_list; li != NULL;
959            li = g_list_next(li)) {
960                AppletData *ad = li->data;
961                if(IS_BUTTON_WIDGET(ad->applet)) {
962                        ButtonWidget *button = BUTTON_WIDGET(ad->applet);
963                        if((even_no_alpha || !button->no_alpha)
964                           && button->cache) {
965                                gdk_pixmap_unref(button->cache);
966                                button->cache = NULL;
967                        }
968                }
969        }
970}
971
972void
973panel_widget_force_repaint (PanelWidget *panel)
974{
975        gtk_widget_queue_clear (GTK_WIDGET (panel));
976        kill_cache_on_all_buttons(panel, TRUE);
977        send_draw_to_all_applets(panel);
978}
979
980/* set up a pixbuf thats the background of the panel */
981void
982panel_widget_setup_translucent_background (PanelWidget *panel)
983{
984        GdkPixmap *pixmap = NULL;
985        GdkBitmap *bitmap = NULL;
986        GdkPixbuf *background = NULL;
987        GdkPixbuf *background_shaded = NULL;
988        GdkWindow *window = gtk_widget_get_parent_window (GTK_WIDGET (panel));
989
990        if (desktop_pixmap && window != NULL) {
991                background = gdk_pixbuf_get_from_drawable (NULL,
992                                desktop_pixmap,
993                                gdk_window_get_colormap (window),
994                                panel->x, panel->y,
995                                0, 0, panel->width, panel->height);
996
997                background_shaded = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE,
998                                8, panel->width, panel->height);
999
1000                gdk_pixbuf_composite_color (background, background_shaded,
1001                                0, 0, panel->width, panel->height,
1002                                0.0, 0.0, 1.0, 1.0,
1003                                GDK_INTERP_NEAREST, TRANSLUCENT_OPACITY,
1004                                0, 0, 100,
1005                                0, 0);
1006
1007                /* render it onto a pixmap to use to tile the background */
1008                gdk_pixbuf_render_pixmap_and_mask (background_shaded, &pixmap,
1009                                &bitmap, 0);
1010
1011                /* and we're finished with it */
1012                if (panel->backpix != NULL) {
1013                        gdk_pixbuf_unref (panel->backpix);
1014                }
1015                panel->backpix = background_shaded;
1016                gdk_pixbuf_unref (background);
1017
1018                if (bitmap != NULL) {
1019                        gdk_bitmap_unref (bitmap);
1020                }
1021                if (pixmap != NULL) {
1022                        if (panel->backpixmap != NULL) {
1023                                gdk_pixmap_unref (panel->backpixmap);
1024                        }
1025                        panel->backpixmap = pixmap;
1026                }
1027        }
1028}
1029
1030static void
1031setup_background(PanelWidget *panel, GdkPixbuf **pb, int *scale_w, int *scale_h,
1032                 gboolean *rotate)
1033{
1034        GtkWidget *widget = GTK_WIDGET(panel);
1035        GdkPixmap *bg_pixmap;
1036       
1037        *pb = NULL;
1038        *scale_w = *scale_h = 0;
1039        *rotate = FALSE;
1040
1041        bg_pixmap = widget->style->bg_pixmap[GTK_WIDGET_STATE(widget)];
1042
1043        if(panel->back_type == PANEL_BACK_NONE) {
1044                if(bg_pixmap && !panel->backpix) {
1045                        int w, h;
1046                        gdk_window_get_size(bg_pixmap, &w, &h);
1047                        panel->backpix = gdk_pixbuf_get_from_drawable
1048                                (NULL, bg_pixmap, widget->style->colormap,
1049                                 0, 0, 0, 0, w, h);
1050                        kill_cache_on_all_buttons(panel, FALSE);
1051                        send_draw_to_all_applets(panel);
1052                } else if(!bg_pixmap && panel->backpix) {
1053                        gdk_pixbuf_unref(panel->backpix);
1054                        panel->backpix = NULL;
1055                        kill_cache_on_all_buttons(panel, FALSE);
1056                        send_draw_to_all_applets(panel);
1057                }
1058                *pb = panel->backpix;
1059        } else if(panel->back_type == PANEL_BACK_PIXMAP) {
1060                if(!panel->backpixmap)
1061                        panel_resize_pixmap(panel);
1062
1063                *pb = panel->backpix;
1064
1065                if(panel->fit_pixmap_bg ||
1066                   panel->strech_pixmap_bg) {
1067                        *scale_w = panel->scale_w;
1068                        *scale_h = panel->scale_h;
1069                        if(panel->orient == PANEL_VERTICAL &&
1070                           panel->rotate_pixmap_bg)
1071                                *rotate = TRUE;
1072                } else {
1073                        if(panel->orient == PANEL_VERTICAL &&
1074                           panel->rotate_pixmap_bg) {
1075                                /* we need to set scales to rotate*/
1076                                *scale_w = gdk_pixbuf_get_width((*pb));
1077                                *scale_h = gdk_pixbuf_get_height((*pb));
1078                                *rotate = TRUE;
1079                        }
1080                }
1081        } else if(panel->back_type == PANEL_BACK_TRANSLUCENT) {
1082                /* YAK: *shrug* */
1083                /* FIXME: make this returnt he right thing! */
1084                *pb = panel->backpix;
1085        }
1086}
1087
1088void
1089panel_widget_draw_all(PanelWidget *panel, GdkRectangle *area)
1090{
1091        GList *li;
1092        GtkWidget *widget;
1093        GdkGC *gc;
1094        GdkPixmap *pixmap;
1095        GdkRectangle da;
1096        GdkPixbuf *pb = NULL;
1097        int size;
1098        int scale_w = 0,scale_h = 0;
1099        int rotate = FALSE;
1100
1101        g_return_if_fail(panel!=NULL);
1102        g_return_if_fail(IS_PANEL_WIDGET(panel));
1103
1104        widget = GTK_WIDGET(panel);
1105
1106#ifdef PANEL_DEBUG
1107        puts("PANEL_WIDGET_DRAW_ALL");
1108#endif
1109
1110        if(!GTK_WIDGET_DRAWABLE(widget) ||
1111           widget->allocation.width <= 0 ||
1112           widget->allocation.height <= 0)
1113                return;
1114
1115        if(area) {
1116                if(area->width==0 || area->height==0)
1117                        return;
1118                da = *area;
1119        } else {
1120                da.x = 0;
1121                da.y = 0;
1122                da.width = widget->allocation.width;
1123                da.height = widget->allocation.height;
1124        }
1125
1126        setup_background(panel, &pb, &scale_w, &scale_h, &rotate);
1127       
1128        pixmap = gdk_pixmap_new(widget->window,
1129                                da.width,da.height,
1130                                gtk_widget_get_visual(widget)->depth);
1131       
1132        gc = gdk_gc_new(pixmap);
1133        gdk_gc_copy(gc,widget->style->bg_gc[GTK_WIDGET_STATE(widget)]);
1134
1135        if(panel->back_type == PANEL_BACK_NONE) {
1136                if(widget->style->bg_pixmap[GTK_WIDGET_STATE(widget)]) {
1137                        gdk_gc_set_fill(gc, GDK_TILED);
1138                        gdk_gc_set_tile(gc,
1139                                        widget->style->bg_pixmap[GTK_WIDGET_STATE(widget)]);
1140                        gdk_gc_set_ts_origin(gc,-da.x,-da.y);
1141                }
1142        } else if(panel->back_type == PANEL_BACK_PIXMAP) {
1143                if(panel->backpixmap) {
1144                        gdk_gc_set_fill(gc, GDK_TILED);
1145                        gdk_gc_set_tile(gc, panel->backpixmap);
1146                        gdk_gc_set_ts_origin(gc,-da.x,-da.y);
1147                }
1148        } else if(panel->back_type == PANEL_BACK_TRANSLUCENT) {
1149                if(panel->backpixmap) {
1150                        gdk_gc_set_fill(gc, GDK_TILED);
1151                        gdk_gc_set_tile(gc, panel->backpixmap);
1152                        gdk_gc_set_ts_origin(gc,-da.x,-da.y);
1153                }
1154        } else /*COLOR*/ {
1155                gdk_gc_set_foreground(gc, &panel->back_color);
1156        }
1157
1158
1159        gdk_draw_rectangle(pixmap,gc, TRUE, 0, 0, -1, -1);
1160
1161        /* get pixel size of an icon */
1162        size = panel->sz;
1163
1164        for(li = panel->applet_list; li != NULL;
1165            li = g_list_next(li)) {
1166                AppletData *ad = li->data;
1167                if(IS_BUTTON_WIDGET(ad->applet) &&
1168                   ad->applet->allocation.x>=0 &&
1169                   (!area || gtk_widget_intersect(ad->applet, area, NULL))) {
1170                        ButtonWidget *button = BUTTON_WIDGET(ad->applet);
1171                        if(!button->cache) {
1172                                guchar *rgb_buf;
1173
1174                                button->cache =
1175                                        gdk_pixmap_new(widget->window, size,size,
1176                                                       gtk_widget_get_visual(widget)->depth);
1177                                rgb_buf = g_new0(guchar, size*size*3);
1178                                /*if the icon doesn't have an opaque tile,
1179                                  draw us a background*/
1180                                if(!button->no_alpha)
1181                                        make_background(panel, rgb_buf,
1182                                                        ad->applet->allocation.x,
1183                                                        ad->applet->allocation.y,
1184                                                        size,size, pb, scale_w, scale_h,
1185                                                        rotate);
1186                                button_widget_draw(button, rgb_buf, size*3);
1187                                gdk_draw_rgb_image(button->cache, gc,
1188                                                   0,0, size, size,
1189                                                   GDK_RGB_DITHER_NORMAL,
1190                                                   rgb_buf, size*3);
1191                                g_free(rgb_buf);
1192                                button_widget_draw_xlib(button, button->cache);
1193                        }
1194                        gdk_draw_pixmap(pixmap,gc,
1195                                        button->cache,
1196                                        0,0,
1197                                        ad->applet->allocation.x - da.x,
1198                                        ad->applet->allocation.y - da.y,
1199                                        size, size);
1200                }
1201        }
1202        gdk_gc_unref(gc);
1203
1204        gdk_draw_pixmap(widget->window,
1205                        widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
1206                        pixmap,
1207                        0,0,da.x,da.y,da.width,da.height);
1208        gdk_pixmap_unref(pixmap);
1209}
1210
1211void
1212panel_widget_draw_icon(PanelWidget *panel, ButtonWidget *button)
1213{
1214        GtkWidget *widget;
1215        GdkRectangle area;
1216
1217        g_return_if_fail(button != NULL);
1218        g_return_if_fail(GTK_IS_WIDGET(button));
1219        g_return_if_fail(panel != NULL);
1220        g_return_if_fail(IS_PANEL_WIDGET(panel));
1221       
1222#ifdef PANEL_DEBUG
1223        puts("PANEL_WIDGET_DRAW_ICON");
1224#endif
1225
1226        widget = GTK_WIDGET(button);
1227       
1228        area.x = widget->allocation.x;
1229        area.y = widget->allocation.y;
1230        area.width = widget->allocation.width;
1231        area.height = widget->allocation.height;
1232
1233        panel_widget_draw_all(panel, &area);
1234}
1235
1236static void
1237panel_widget_draw(GtkWidget *widget, GdkRectangle *area)
1238{
1239        GList *li;
1240        PanelWidget *panel;
1241
1242        g_return_if_fail(widget!=NULL);
1243        g_return_if_fail(IS_PANEL_WIDGET(widget));
1244       
1245#ifdef PANEL_DEBUG
1246        puts("PANEL_WIDGET_DRAW");
1247       
1248        printf("allocation %d x %d\n",
1249               widget->allocation.width,
1250               widget->allocation.height);
1251#endif
1252
1253        panel = PANEL_WIDGET(widget);
1254
1255        if(!GTK_WIDGET_DRAWABLE(widget) ||
1256           panel->inhibit_draw)
1257                return;
1258
1259        panel_widget_draw_all(panel, area);
1260
1261        for(li = panel->applet_list;
1262            li != NULL;
1263            li = g_list_next(li)) {
1264                AppletData *ad = li->data;
1265                GdkRectangle ch_area;
1266                if(!IS_BUTTON_WIDGET(ad->applet) &&
1267                   gtk_widget_intersect(ad->applet, area, &ch_area))
1268                        gtk_widget_draw(ad->applet, &ch_area);
1269        }
1270}
1271
1272static int
1273panel_widget_expose(GtkWidget *widget, GdkEventExpose *event)
1274{
1275        GList *li;
1276        PanelWidget *panel;
1277
1278        g_return_val_if_fail(widget!=NULL,FALSE);
1279        g_return_val_if_fail(IS_PANEL_WIDGET(widget),FALSE);
1280        g_return_val_if_fail(event!=NULL,FALSE);
1281
1282        panel = PANEL_WIDGET(widget);
1283
1284        if(!GTK_WIDGET_DRAWABLE(widget))
1285                return FALSE;
1286       
1287#ifdef PANEL_DEBUG
1288        puts("PANEL_WIDGET_EXPOSE");
1289#endif
1290
1291        panel_widget_draw_all(panel, &event->area);
1292
1293        for(li = panel->applet_list;
1294            li != NULL;
1295            li = g_list_next(li)) {
1296                AppletData *ad = li->data;
1297                GdkEventExpose ch_event = *event;
1298
1299                if(!IS_BUTTON_WIDGET(ad->applet) &&
1300                   GTK_WIDGET_NO_WINDOW (ad->applet) &&
1301                   gtk_widget_intersect (ad->applet, &event->area,
1302                                         &ch_event.area))
1303                        gtk_widget_event (ad->applet, (GdkEvent*) &ch_event);
1304        }
1305
1306        return FALSE;
1307}
1308
1309static void
1310panel_widget_size_allocate(GtkWidget *widget, GtkAllocation *allocation)
1311{
1312        PanelWidget *panel;
1313        GList *list;
1314        GSList *send_move = NULL;
1315        GSList *li;
1316        int i;
1317        int old_size;
1318        int old_thick;
1319        GtkAllocation old_alloc;
1320        int side_padding;
1321
1322        g_return_if_fail(widget!=NULL);
1323        g_return_if_fail(IS_PANEL_WIDGET(widget));
1324        g_return_if_fail(allocation!=NULL);
1325       
1326        panel = PANEL_WIDGET(widget);
1327
1328#ifdef PANEL_DEBUG
1329        puts("PANEL_WIDGET_SIZE_ALLOCATE");
1330        printf("allocation %d x %d\n",
1331               allocation->width,
1332               allocation->height);
1333#endif
1334
1335        /* allow drawing if it was inhibited */
1336        panel->inhibit_draw = FALSE;
1337       
1338        old_size = panel->size;
1339        old_thick = panel->thick;
1340       
1341        old_alloc = widget->allocation;
1342
1343        if((widget->allocation.width != allocation->width ||
1344            widget->allocation.height != allocation->height) &&
1345           panel->back_type != PANEL_BACK_COLOR &&
1346           (panel->back_type != PANEL_BACK_NONE ||
1347            GTK_WIDGET(panel)->style->bg_pixmap[GTK_WIDGET_STATE(panel)])) {
1348                kill_cache_on_all_buttons(panel, FALSE);
1349                send_draw_to_all_applets(panel);
1350        }
1351       
1352        widget->allocation = *allocation;
1353        if (GTK_WIDGET_REALIZED (widget))
1354                gdk_window_move_resize (widget->window,
1355                                        allocation->x,
1356                                        allocation->y,
1357                                        allocation->width,
1358                                        allocation->height);
1359
1360        if(panel->orient == PANEL_HORIZONTAL)
1361                panel->size = allocation->width;
1362        else
1363                panel->size = allocation->height;
1364        if(old_size<panel->size)
1365                panel_widget_right_stick(panel,old_size);
1366
1367        if(panel->no_padding_on_ends)
1368                side_padding = 0;
1369        else
1370                side_padding = pw_applet_padding;
1371
1372        if(panel->packed) {
1373                i = side_padding;
1374                for(list = panel->applet_list;
1375                    list!=NULL;
1376                    list = g_list_next(list)) {
1377                        AppletData *ad = list->data;
1378                        GtkAllocation challoc;
1379                        GtkRequisition chreq;
1380                        gtk_widget_get_child_requisition(ad->applet,&chreq);
1381                       
1382                        if(i != ad->pos) {
1383                                ad->pos = i;
1384                                send_move = g_slist_prepend(send_move,ad);
1385                        }
1386                        if(panel->orient == PANEL_HORIZONTAL) {
1387                                ad->cells = chreq.width;
1388                                challoc.x = ad->pos;
1389                                challoc.y = (allocation->height - chreq.height) / 2;
1390                        } else {
1391                                ad->cells = chreq.height;
1392                                challoc.x = (allocation->width - chreq.width) / 2;
1393                                challoc.y = ad->pos;
1394                        }
1395                        if(list->next)
1396                                ad->cells += pw_applet_padding;
1397                        else
1398                                ad->cells += side_padding;
1399                        challoc.width = chreq.width;
1400                        challoc.height = chreq.height;
1401                        ad->dirty = FALSE;
1402                        gtk_widget_size_allocate(ad->applet,&challoc);
1403                        i += ad->cells;
1404                }
1405        } else { /*not packed*/
1406                i = panel->size;
1407                for(list = g_list_last(panel->applet_list);
1408                    list!=NULL;
1409                    list = g_list_previous(list)) {
1410                        AppletData *ad = list->data;
1411                        GtkRequisition chreq;
1412                        gtk_widget_get_child_requisition(ad->applet,&chreq);
1413
1414                        if(panel->orient == PANEL_HORIZONTAL)
1415                                ad->cells = chreq.width;
1416                        else
1417                                ad->cells = chreq.height;
1418                       
1419                        if(list->next)
1420                                ad->cells += pw_applet_padding;
1421                        else
1422                                ad->cells += side_padding;
1423
1424                        if(ad->pos+ad->cells > i) {
1425                                ad->pos = i - ad->cells;
1426                                send_move = g_slist_prepend(send_move,ad);
1427                        }
1428                        i = ad->pos;
1429                }
1430                if(i<side_padding) {
1431                        i = side_padding;
1432                        for(list = panel->applet_list;
1433                            list!=NULL;
1434                            list = g_list_next(list)) {
1435                                AppletData *ad = list->data;
1436                               
1437                                if(ad->pos < i) {
1438                                        ad->pos = i;
1439                                        if(!g_slist_find(send_move,ad))
1440                                                send_move = g_slist_prepend(send_move,ad);
1441                                }
1442                               
1443                                i = ad->pos + ad->cells;
1444                        }
1445                }
1446
1447                for(list = panel->applet_list;
1448                    list!=NULL;
1449                    list = g_list_next(list)) {
1450                        AppletData *ad = list->data;
1451                        GtkAllocation challoc;
1452                        GtkRequisition chreq;
1453                        gtk_widget_get_child_requisition(ad->applet,&chreq);
1454                        if(panel->orient == PANEL_HORIZONTAL) {
1455                                challoc.x = ad->pos;
1456                                challoc.y = (allocation->height - chreq.height) / 2;
1457                        } else {
1458                                challoc.x = (allocation->width - chreq.width) / 2;
1459                                challoc.y = ad->pos;
1460                        }
1461                        challoc.width = chreq.width;
1462                        challoc.height = chreq.height;
1463                        ad->dirty = FALSE;
1464                        gtk_widget_size_allocate(ad->applet,&challoc);
1465                }
1466        }
1467        if(panel->orient == PANEL_HORIZONTAL)
1468                panel->thick = allocation->height;
1469        else
1470                panel->thick = allocation->width;
1471
1472        if(panel->back_type == PANEL_BACK_PIXMAP &&
1473           (panel->fit_pixmap_bg || panel->strech_pixmap_bg) &&
1474           (old_alloc.width != allocation->width ||
1475            old_alloc.height != allocation->height)) {
1476                if(panel->backpixmap) {
1477                        gdk_pixmap_unref(panel->backpixmap);
1478                        panel->backpixmap = NULL;
1479                }
1480        }
1481
1482        if (panel->back_type == PANEL_BACK_TRANSLUCENT &&
1483                        GTK_WIDGET(panel)->window != NULL) {
1484                panel->width = allocation->width;
1485                panel->height = allocation->height;
1486                gdk_window_get_deskrelative_origin (GTK_WIDGET(panel)->window,
1487                                &panel->x, &panel->y);
1488                panel_widget_setup_translucent_background (panel);
1489        }
1490
1491        for(li=send_move;li!=NULL;li=g_slist_next(li)) {
1492                AppletData *ad = li->data;
1493                gtk_signal_emit(GTK_OBJECT(panel),
1494                                panel_widget_signals[APPLET_MOVE_SIGNAL],
1495                                ad->applet);
1496        }
1497        g_slist_free(send_move);
1498       
1499        if (GTK_WIDGET_REALIZED (widget))
1500                panel_widget_draw_all(panel,NULL);
1501}
1502
1503gboolean
1504panel_widget_is_cursor(PanelWidget *panel, int overlap)
1505{
1506        int x,y;
1507        int w,h;
1508        GtkWidget *widget;
1509
1510        g_return_val_if_fail(panel!=NULL,FALSE);
1511        g_return_val_if_fail(IS_PANEL_WIDGET(panel),FALSE);
1512
1513        widget = panel->drop_widget;
1514       
1515        if(!widget ||
1516           !GTK_IS_WIDGET(widget) ||
1517           !GTK_WIDGET_VISIBLE(widget))
1518                return FALSE;
1519
1520        gtk_widget_get_pointer(widget, &x, &y);
1521        w = widget->allocation.width;
1522        h = widget->allocation.height;
1523
1524        if((x+overlap)>=0 &&
1525           (x-overlap)<=w &&
1526           (y+overlap)>=0 &&
1527           (y-overlap)<=h)
1528                return TRUE;
1529        return FALSE;
1530}
1531
1532void
1533panel_widget_set_back_pixmap (PanelWidget *panel, char *file)
1534{
1535        g_return_if_fail(panel!=NULL);
1536        g_return_if_fail(IS_PANEL_WIDGET(panel));
1537        g_return_if_fail(file!=NULL);
1538
1539#ifdef PANEL_DEBUG
1540        puts("PANEL_WIDGET_SET_BACK_PIXMAP");
1541#endif
1542
1543        if (panel_try_to_set_pixmap (panel, file)) {
1544                g_free (panel->back_pixmap);
1545                panel->back_pixmap = g_strdup (file);
1546                panel->back_type = PANEL_BACK_PIXMAP;
1547                panel_widget_draw_all(panel,NULL);
1548
1549                gtk_signal_emit(GTK_OBJECT(panel),
1550                                panel_widget_signals[BACK_CHANGE_SIGNAL],
1551                                panel->back_type,
1552                                panel->back_pixmap,
1553                                &panel->back_color);
1554        } else
1555                panel_widget_draw_all(panel,NULL);
1556}
1557
1558static void
1559panel_try_to_set_back_color(PanelWidget *panel, GdkColor *color)
1560{
1561        GdkColormap *cmap;
1562
1563        g_return_if_fail(panel!=NULL);
1564        g_return_if_fail(IS_PANEL_WIDGET(panel));
1565        g_return_if_fail(color!=NULL);
1566       
1567        kill_cache_on_all_buttons(panel, FALSE);
1568        send_draw_to_all_applets(panel);
1569
1570        cmap = gtk_widget_get_colormap(GTK_WIDGET(panel));
1571
1572        if(gdk_colormap_alloc_color(cmap,color,FALSE,TRUE)) {
1573                panel->back_color = *color;
1574        }
1575}
1576
1577void
1578panel_widget_set_back_color(PanelWidget *panel, GdkColor *color)
1579{
1580        g_return_if_fail(panel!=NULL);
1581        g_return_if_fail(IS_PANEL_WIDGET(panel));
1582        g_return_if_fail(color!=NULL);
1583
1584        panel->back_type = PANEL_BACK_COLOR;
1585        panel_try_to_set_back_color(panel, color);
1586        panel_widget_draw_all(panel,NULL);
1587
1588        gtk_signal_emit(GTK_OBJECT(panel),
1589                        panel_widget_signals[BACK_CHANGE_SIGNAL],
1590                        panel->back_type,
1591                        panel->back_pixmap,
1592                        &panel->back_color);
1593}
1594
1595static GdkPixmap *
1596get_pixmap_from_pixbuf(GtkWidget *w, GdkPixbuf *pb, int scale_w, int scale_h,
1597                       int rotate)
1598{
1599        GdkGC *gc;
1600        GdkPixmap *p;
1601        gdouble affine[6];
1602        guchar *rgb;
1603       
1604        affine[1] = affine[2] = affine[4] = affine[5] = 0;
1605
1606        affine[0] = scale_w / (double)(gdk_pixbuf_get_width(pb));
1607        affine[3] = scale_h / (double)(gdk_pixbuf_get_height(pb));
1608
1609        if(rotate) {
1610                int tmp;
1611                gdouble aff[6];
1612
1613                art_affine_rotate(aff,270);
1614                art_affine_multiply(affine,affine,aff);
1615                art_affine_translate(aff,0,scale_w);
1616                art_affine_multiply(affine,affine,aff);
1617               
1618                tmp = scale_h;
1619                scale_h = scale_w;
1620                scale_w = tmp;
1621        }
1622       
1623        rgb = g_new0(guchar,scale_h*scale_w*3);
1624#ifdef PANEL_DEBUG
1625        printf("scale_w %d scale_h %d\n",scale_w,scale_h);
1626#endif
1627        transform_pixbuf(rgb,
1628                         0,0,scale_w,scale_h,scale_w*3,
1629                         pb,affine,ART_FILTER_NEAREST,NULL);
1630        p = gdk_pixmap_new(w->window, scale_w,scale_h,
1631                           gtk_widget_get_visual(GTK_WIDGET(w))->depth);
1632        gc = gdk_gc_new(p);
1633        gdk_draw_rgb_image(p,gc,0,0,
1634                           scale_w,scale_h,
1635                           GDK_RGB_DITHER_NORMAL,
1636                           rgb, scale_w*3);
1637        g_free(rgb);
1638        gdk_gc_destroy(gc);
1639
1640        return p;
1641}
1642
1643
1644static void
1645panel_resize_pixmap(PanelWidget *panel)
1646{
1647        int w, h;
1648        int pw, ph;
1649
1650        g_return_if_fail(panel!=NULL);
1651        g_return_if_fail(IS_PANEL_WIDGET(panel));
1652
1653        if(panel->backpixmap)
1654                gdk_pixmap_unref(panel->backpixmap);
1655        panel->backpixmap = NULL;
1656       
1657        if(!panel->backpix) return;
1658       
1659        panel->scale_w = w = gdk_pixbuf_get_width(panel->backpix);
1660        panel->scale_h = h = gdk_pixbuf_get_height(panel->backpix);
1661       
1662        pw = GTK_WIDGET(panel)->allocation.width;
1663        ph = GTK_WIDGET(panel)->allocation.height;
1664
1665        if(panel->fit_pixmap_bg) {
1666                switch (panel->orient) {
1667                case PANEL_HORIZONTAL:
1668                        panel->scale_w = w * ph / h;
1669                        panel->scale_h = ph;
1670                        break;
1671
1672                case PANEL_VERTICAL:
1673                        if(panel->rotate_pixmap_bg) {
1674                                panel->scale_w = w * pw / h;
1675                                panel->scale_h = pw;
1676                        } else {
1677                                panel->scale_w = pw;
1678                                panel->scale_h = h * pw / w;
1679                        }
1680                        break;
1681
1682                default:
1683                        g_assert_not_reached ();
1684                }
1685        } else if(panel->strech_pixmap_bg) {
1686                if(panel->orient == PANEL_VERTICAL &&
1687                   panel->rotate_pixmap_bg) {
1688                        panel->scale_w = ph;
1689                        panel->scale_h = pw;
1690                } else {
1691                        panel->scale_w = pw;
1692                        panel->scale_h = ph;
1693                }
1694        }
1695       
1696        panel->backpixmap = get_pixmap_from_pixbuf(
1697                                        GTK_WIDGET(panel),
1698                                        panel->backpix,
1699                                        panel->scale_w,
1700                                        panel->scale_h,
1701                                        panel->orient == PANEL_VERTICAL &&
1702                                        panel->rotate_pixmap_bg);
1703}
1704
1705static int
1706panel_try_to_set_pixmap (PanelWidget *panel, char *pixmap)
1707{
1708        g_return_val_if_fail(panel!=NULL,FALSE);
1709        g_return_val_if_fail(IS_PANEL_WIDGET(panel),FALSE);
1710
1711        kill_cache_on_all_buttons(panel, FALSE);
1712        send_draw_to_all_applets(panel);
1713
1714        if(panel->backpix)
1715                gdk_pixbuf_unref(panel->backpix);
1716        panel->backpix = NULL;
1717        if (panel->backpixmap != NULL)
1718                gdk_pixmap_unref (panel->backpixmap);
1719        panel->backpixmap = NULL;
1720
1721        if (string_empty (pixmap)) {
1722                return TRUE;
1723        }
1724
1725        if ( ! panel_file_exists (pixmap))
1726                return FALSE;
1727       
1728        panel->backpix = gdk_pixbuf_new_from_file (pixmap);
1729        if (panel->backpix == NULL)
1730                return FALSE;
1731
1732        panel->scale_w = gdk_pixbuf_get_width (panel->backpix);
1733        panel->scale_h = gdk_pixbuf_get_height (panel->backpix);
1734
1735        return TRUE;
1736}
1737
1738static int
1739panel_try_to_set_translucent (PanelWidget *panel)
1740{
1741        g_return_val_if_fail(panel!=NULL,FALSE);
1742        g_return_val_if_fail(IS_PANEL_WIDGET(panel),FALSE);
1743
1744        kill_cache_on_all_buttons(panel, FALSE);
1745        send_draw_to_all_applets(panel);
1746
1747        panel_widget_setup_translucent_background (panel);
1748
1749        return TRUE;
1750}
1751
1752static void
1753panel_widget_realize(GtkWidget *w, gpointer data)
1754{
1755        PanelWidget *panel;
1756
1757        g_return_if_fail(w!=NULL);
1758        g_return_if_fail(IS_PANEL_WIDGET(w));
1759
1760        panel = PANEL_WIDGET(w);
1761
1762        if(panel->back_type == PANEL_BACK_PIXMAP) {
1763                if (!panel_try_to_set_pixmap (panel, panel->back_pixmap))
1764                        panel->back_type = PANEL_BACK_NONE;
1765        } else if(panel->back_type == PANEL_BACK_TRANSLUCENT) {
1766                /* YAK: hmm */
1767        } else if(panel->back_type == PANEL_BACK_COLOR) {
1768                panel_try_to_set_back_color(panel, &panel->back_color);
1769        }
1770
1771#ifdef PANEL_DEBUG
1772        puts("PANEL_WIDGET_REALIZE");
1773#endif
1774        panel_widget_draw_all(panel,NULL);
1775}
1776
1777static void
1778panel_widget_destroy(GtkWidget *w, gpointer data)
1779{
1780        PanelWidget *panel;
1781
1782        g_return_if_fail(w!=NULL);
1783        g_return_if_fail(IS_PANEL_WIDGET(w));
1784
1785        panel = PANEL_WIDGET(w);
1786
1787        if(panel->backpix)
1788                gdk_pixbuf_unref(panel->backpix);
1789        panel->backpix = NULL;
1790
1791        g_free (panel->back_pixmap);
1792        panel->back_pixmap = NULL;
1793
1794        /*remove from panels list*/
1795        panels = g_slist_remove(panels,w);
1796}
1797
1798static void
1799panel_widget_style_set(PanelWidget *panel)
1800{
1801        if(panel->back_type == PANEL_BACK_NONE) {
1802                if(panel->backpix)
1803                        gdk_pixbuf_unref(panel->backpix);
1804                panel->backpix = NULL;
1805                kill_cache_on_all_buttons(panel, TRUE);
1806                send_draw_to_all_applets(panel);
1807        }
1808}
1809
1810static gboolean panel_widget_applet_event(GtkWidget *widget, GdkEvent *event, gpointer data);
1811
1812static gboolean
1813is_in_widget(GdkEventButton *bevent, GtkWidget *widget)
1814{
1815        g_return_val_if_fail(widget!=NULL,FALSE);
1816        g_return_val_if_fail(GTK_IS_WIDGET(widget),FALSE);
1817        g_return_val_if_fail(bevent!=NULL,FALSE);
1818
1819        if(bevent->x >= widget->allocation.x &&
1820           bevent->x < (widget->allocation.x + widget->allocation.width) &&
1821           bevent->y >= widget->allocation.y &&
1822           bevent->y < (widget->allocation.y + widget->allocation.height))
1823                return TRUE;
1824        return FALSE;
1825}
1826
1827static gboolean
1828panel_widget_event(GtkWidget *widget, GdkEvent *event, gpointer data)
1829{
1830        PanelWidget *panel;
1831        GList *list;
1832        GdkEventButton *bevent;
1833
1834        g_return_val_if_fail(widget!=NULL,FALSE);
1835        g_return_val_if_fail(IS_PANEL_WIDGET(widget),FALSE);
1836        g_return_val_if_fail(event!=NULL,FALSE);
1837
1838        panel = PANEL_WIDGET(widget);
1839        bevent = (GdkEventButton *) event;
1840
1841        if((event->type != GDK_BUTTON_PRESS &&
1842            event->type != GDK_BUTTON_RELEASE) ||
1843           bevent->window != widget->window)
1844                return FALSE;
1845
1846        for(list = panel->no_window_applet_list; list!=NULL;
1847            list = g_list_next(list)) {
1848                AppletData *ad = list->data;
1849                if(is_in_widget(bevent,ad->applet) &&
1850                   bevent->button != 1)
1851                        return panel_widget_applet_event(ad->applet,
1852                                                         event,data);
1853        }
1854        return FALSE;
1855}
1856
1857PanelWidget *
1858panel_widget_get_by_id (gint32 id)
1859{
1860        GSList *li;
1861
1862        for (li = panels; li != NULL; li = li->next) {
1863                PanelWidget *panel = li->data;
1864
1865                if (panel->unique_id == id)
1866                        return panel;
1867        }
1868
1869        return NULL;
1870}
1871
1872void
1873panel_widget_set_id (PanelWidget *panel, gint32 id)
1874{
1875        panel->unique_id = id;
1876}
1877
1878static gint32
1879generate_unique_id (void)
1880{
1881        gint32 id;
1882        GTimeVal tv;
1883        static int incr = -1;
1884
1885        if (incr == -1)
1886                incr = (rand () >> 3) & 0xFF;
1887
1888        id = (rand () >> 3) && 0xFFF;
1889        id += (incr << 12);
1890
1891        g_get_current_time (&tv);
1892        id += (tv.tv_usec & 0x7FF) << 20;
1893
1894        incr ++;
1895
1896        if (panel_widget_get_by_id (id) != NULL)
1897                id = generate_unique_id ();
1898
1899        return id;
1900}
1901
1902static void
1903panel_widget_init (PanelWidget *panel)
1904{
1905        g_return_if_fail(panel!=NULL);
1906        g_return_if_fail(IS_PANEL_WIDGET(panel));
1907
1908        panel->unique_id = generate_unique_id ();
1909
1910        /*this makes the popup "pop down" once the button is released*/
1911        gtk_widget_set_events(GTK_WIDGET(panel),
1912                              gtk_widget_get_events(GTK_WIDGET(panel)) |
1913                              GDK_BUTTON_RELEASE_MASK);
1914       
1915        panel->back_type =PANEL_BACK_NONE;
1916        panel->fit_pixmap_bg = FALSE;
1917        panel->strech_pixmap_bg = FALSE;
1918        panel->back_pixmap = NULL;
1919        panel->back_color.red = 0;
1920        panel->back_color.green = 0;
1921        panel->back_color.blue = 0;
1922        panel->back_color.pixel = 1;
1923        panel->packed = FALSE;
1924        panel->orient = PANEL_HORIZONTAL;
1925        panel->thick = PANEL_MINIMUM_WIDTH;
1926        panel->size = G_MAXINT;
1927        panel->applet_list = NULL;
1928        panel->no_window_applet_list = NULL;
1929        panel->master_widget = NULL;
1930        panel->drop_widget = GTK_WIDGET(panel);
1931        panel->backpix = NULL;
1932        panel->backpixmap = NULL;
1933        panel->inhibit_draw = FALSE;
1934
1935        gtk_signal_connect(GTK_OBJECT(panel),
1936                           "destroy",
1937                           GTK_SIGNAL_FUNC(panel_widget_destroy),
1938                           NULL);
1939        gtk_signal_connect(GTK_OBJECT(panel),
1940                           "style_set",
1941                           GTK_SIGNAL_FUNC(panel_widget_style_set),
1942                           NULL);
1943        gtk_signal_connect(GTK_OBJECT(panel),
1944                           "event",
1945                           GTK_SIGNAL_FUNC(panel_widget_event),
1946                           NULL);
1947
1948        panels = g_slist_append(panels,panel);
1949}
1950
1951GtkWidget *
1952panel_widget_new (gboolean packed,
1953                  PanelOrientation orient,
1954                  int sz,
1955                  PanelBackType back_type,
1956                  char *back_pixmap,
1957                  gboolean fit_pixmap_bg,
1958                  gboolean strech_pixmap_bg,
1959                  gboolean rotate_pixmap_bg,
1960                  gboolean no_padding_on_ends,
1961                  GdkColor *back_color)
1962{
1963        PanelWidget *panel;
1964
1965        panel = gtk_type_new(panel_widget_get_type());
1966
1967        panel->back_type = back_type;
1968
1969        panel->fit_pixmap_bg = fit_pixmap_bg;
1970        panel->strech_pixmap_bg = strech_pixmap_bg;
1971        panel->rotate_pixmap_bg = rotate_pixmap_bg;
1972        panel->back_pixmap = g_strdup (sure_string (back_pixmap));
1973        panel->no_padding_on_ends = no_padding_on_ends;
1974       
1975        if(back_color)
1976                panel->back_color = *back_color;
1977        else {
1978                panel->back_color.red = 0;
1979                panel->back_color.green = 0;
1980                panel->back_color.blue = 0;
1981                panel->back_color.pixel = 1;
1982        }       
1983
1984        panel->orient = orient;
1985        panel->sz = sz;
1986
1987#ifdef PANEL_DEBUG
1988        printf("GOT SIZE OF %d\n",sz);
1989#endif
1990
1991        panel->packed = packed;
1992        if(packed)
1993                panel->size = 0;
1994        else
1995                panel->size = G_MAXINT;
1996       
1997        gtk_signal_connect_after(GTK_OBJECT(panel),
1998                                 "realize",
1999                                 GTK_SIGNAL_FUNC(panel_widget_realize),
2000                                 panel);
2001
2002        return GTK_WIDGET(panel);
2003}
2004
2005static guint moving_timeout = 0;
2006static gboolean been_moved = FALSE;
2007static gboolean repeat_if_outside = FALSE;
2008
2009void
2010panel_widget_applet_drag_start_no_grab (PanelWidget *panel,
2011                                        GtkWidget *applet,
2012                                        int drag_off)
2013{
2014        AppletData *ad;
2015
2016        g_return_if_fail (panel != NULL);
2017        g_return_if_fail (IS_PANEL_WIDGET (panel));
2018        g_return_if_fail (applet != NULL);
2019        g_return_if_fail (GTK_IS_WIDGET (panel));
2020
2021        ad = gtk_object_get_data (GTK_OBJECT (applet), PANEL_APPLET_DATA);
2022        g_return_if_fail (ad != NULL);
2023
2024        if (moving_timeout != 0) {
2025                gtk_timeout_remove (moving_timeout);
2026                moving_timeout = 0;
2027                been_moved = FALSE;
2028        }
2029
2030#ifdef PANEL_DEBUG
2031        g_message("Starting drag on a %s at %p\n",
2032                  gtk_type_name(GTK_OBJECT(applet)->klass->type), applet);
2033#endif
2034        panel->currently_dragged_applet = ad;
2035        if (drag_off == PW_DRAG_OFF_CURSOR)
2036                ad->drag_off = panel_widget_get_cursorloc (panel) - ad->pos;
2037        else if (drag_off == PW_DRAG_OFF_CENTER)
2038                ad->drag_off = ad->cells / 2;
2039        else
2040                ad->drag_off = drag_off;
2041
2042        panel_applet_in_drag = TRUE;
2043}
2044
2045
2046void
2047panel_widget_applet_drag_end_no_grab (PanelWidget *panel)
2048{
2049        g_return_if_fail (panel != NULL);
2050        g_return_if_fail (IS_PANEL_WIDGET (panel));
2051
2052#ifdef PANEL_DEBUG
2053        g_message("Ending drag\n");
2054#endif
2055        panel->currently_dragged_applet = NULL;
2056        panel_applet_in_drag = FALSE;
2057
2058        if (moving_timeout != 0) {
2059                gtk_timeout_remove (moving_timeout);
2060                moving_timeout = 0;
2061                been_moved = FALSE;
2062        }
2063}
2064
2065void
2066panel_widget_applet_drag_start (PanelWidget *panel,
2067                                GtkWidget *applet,
2068                                int drag_off)
2069{
2070        g_return_if_fail (panel !=NULL);
2071        g_return_if_fail (IS_PANEL_WIDGET (panel));
2072        g_return_if_fail (applet != NULL);
2073        g_return_if_fail (GTK_IS_WIDGET (panel));
2074
2075#ifdef PANEL_DEBUG
2076        g_message("Starting drag [grabbed] on a %s at %p\n",
2077                  gtk_type_name(GTK_OBJECT(applet)->klass->type), applet);
2078#endif
2079        panel_widget_applet_drag_start_no_grab (panel, applet, drag_off);
2080
2081        gtk_grab_add (applet);
2082        if (applet->window != NULL) {
2083                GdkCursor *fleur_cursor = gdk_cursor_new (GDK_FLEUR);
2084                gdk_pointer_grab (applet->window,
2085                                  FALSE,
2086                                  APPLET_EVENT_MASK,
2087                                  NULL,
2088                                  fleur_cursor,
2089                                  GDK_CURRENT_TIME);
2090                gdk_cursor_destroy (fleur_cursor);
2091                gdk_flush ();
2092        }
2093}
2094
2095void
2096panel_widget_applet_drag_end (PanelWidget *panel)
2097{
2098        g_return_if_fail (panel != NULL);
2099        g_return_if_fail (IS_PANEL_WIDGET (panel));
2100
2101        if (panel->currently_dragged_applet == NULL)
2102                return;
2103        gdk_pointer_ungrab (GDK_CURRENT_TIME);
2104        gtk_grab_remove (panel->currently_dragged_applet->applet);
2105        panel_widget_applet_drag_end_no_grab (panel);
2106        gdk_flush ();
2107}
2108
2109/*get pos of the cursor location*/
2110int
2111panel_widget_get_cursorloc (PanelWidget *panel)
2112{
2113        int x, y;
2114
2115        g_return_val_if_fail (panel != NULL, -1);
2116        g_return_val_if_fail (IS_PANEL_WIDGET (panel), -1);
2117
2118        gtk_widget_get_pointer (GTK_WIDGET (panel), &x, &y);
2119
2120        if (panel->orient == PANEL_HORIZONTAL)
2121                return x;
2122        else
2123                return y;
2124}
2125
2126/*get amount of free space around the applet (including the applet size),
2127  or return 0 on error or if the panel is packed*/
2128int
2129panel_widget_get_free_space(PanelWidget *panel, GtkWidget *applet)
2130{
2131        int right,left;
2132        GList *li;
2133        AppletData *ad;
2134
2135        g_return_val_if_fail(panel!=NULL, 0);
2136        g_return_val_if_fail(IS_PANEL_WIDGET(panel), 0);
2137        g_return_val_if_fail(applet!=NULL, 0);
2138        g_return_val_if_fail(GTK_IS_WIDGET(applet), 0);
2139       
2140        /*this function doesn't make sense on packed panels*/
2141        if(panel->packed)
2142                return 0;
2143       
2144        if(panel->no_padding_on_ends) {
2145                right = panel->size;
2146                left = 0;
2147        } else {
2148                right = panel->size - pw_applet_padding;
2149                left = pw_applet_padding;
2150        }
2151       
2152        for(li = panel->applet_list; li; li = g_list_next(li)) {
2153                ad = li->data;
2154                if(ad->applet == applet)
2155                        break;
2156        }
2157        /*the applet is not on this panel*/
2158        if(!li)
2159                return 0;
2160       
2161        if(li->prev) {
2162                AppletData *pad = li->prev->data;
2163                left = pad->pos+pad->cells + pw_applet_padding;
2164        }
2165        if(li->next) {
2166                AppletData *nad = li->next->data;
2167                right = nad->pos - pw_applet_padding;
2168        }
2169       
2170        return right - left;
2171}
2172
2173/*calculates the value to move the applet by*/
2174static int
2175panel_widget_get_moveby (PanelWidget *panel, int pos, int offset)
2176{
2177        g_return_val_if_fail (panel != NULL, -1);
2178        g_return_val_if_fail (IS_PANEL_WIDGET (panel), -1);
2179
2180        return panel_widget_get_cursorloc (panel) - offset - pos;
2181}
2182
2183static GList *
2184walk_up_to (int pos, GList *list)
2185{
2186        AppletData *ad;
2187
2188        g_return_val_if_fail (list != NULL, NULL);
2189
2190        ad = list->data;
2191
2192        if (ad->pos <= pos &&
2193            ad->pos + ad->cells > pos)
2194                return list;
2195        while (list->next != NULL &&
2196               ad->pos + ad->cells <= pos) {
2197                list = list->next;
2198                ad = list->data;
2199        }
2200        while (list->prev != NULL &&
2201               ad->pos > pos) {
2202                list = list->prev;
2203                ad = list->data;
2204        }
2205        return list;
2206}
2207
2208static GtkWidget *
2209is_in_applet (int pos, AppletData *ad)
2210{
2211        g_return_val_if_fail (ad != NULL, NULL);
2212
2213        if (ad->pos <= pos &&
2214            ad->pos + ad->cells > pos)
2215                return ad->applet;
2216        return NULL;
2217}
2218
2219static int
2220panel_widget_get_free_spot (PanelWidget *panel, AppletData *ad)
2221{
2222        int i, e;
2223        int place;
2224        int start;
2225        int right = -1, left = -1;
2226        GList *list;
2227        int side_padding;
2228
2229        g_return_val_if_fail (panel != NULL, -1);
2230        g_return_val_if_fail (IS_PANEL_WIDGET (panel), -1);
2231        g_return_val_if_fail (ad != NULL, -1);
2232
2233        place = panel_widget_get_cursorloc (panel);
2234
2235        if (ad->pos >= panel->size)
2236                return -1;
2237
2238        if (panel->applet_list == NULL) {
2239                if (place + ad->cells>panel->size)
2240                        return panel->size-ad->cells;
2241                else
2242                        return place;
2243        }
2244
2245        list = panel->applet_list;
2246
2247        if (panel->no_padding_on_ends)
2248                side_padding = 0;
2249        else
2250                side_padding = pw_applet_padding;
2251
2252        start = place - ad->drag_off;
2253        if (start < side_padding)
2254                start = side_padding;
2255        for (e = 0, i = start; i < panel->size; i++) {
2256                GtkWidget *applet;
2257                list = walk_up_to (i, list);
2258                applet = is_in_applet (i, list->data);
2259                if (applet == NULL ||
2260                    applet == ad->applet) {
2261                        e++;
2262                        if (e >= ad->cells) {
2263                                right = i - e + 1;
2264                                break;
2265                        }
2266                } else {
2267                        e = 0;
2268                }
2269        }
2270
2271        start = place + ad->drag_off;
2272        if (start >= panel->size)
2273                start = panel->size - 1;
2274        for (e = 0, i = start; i >= 0; i--) {
2275                GtkWidget *applet;
2276                list = walk_up_to (i, list);
2277                applet = is_in_applet (i, list->data);
2278                if (applet == NULL ||
2279                    applet == ad->applet) {
2280                        e++;
2281                        if (e >= ad->cells) {
2282                                left = i;
2283                                break;
2284                        }
2285                } else {
2286                        e=0;
2287                }
2288        }
2289
2290        start = place - ad->drag_off;
2291
2292        if (left == -1) {
2293                if (right == -1)
2294                        return -1;
2295                else
2296                        return right;
2297        } else {
2298                if (right == -1)
2299                        return left;
2300                else
2301                        return abs (left - start) > abs (right - start) ?
2302                                right : left;
2303        }
2304}
2305
2306/*to call this function we MUST know that there is at least
2307  ad->cells free at pos otherwise we will mess up the panel*/
2308static void
2309panel_widget_nice_move (PanelWidget *panel, AppletData *ad, int pos)
2310{
2311        g_return_if_fail (panel != NULL);
2312        g_return_if_fail (IS_PANEL_WIDGET (panel));
2313        g_return_if_fail (ad != NULL);
2314
2315        if (pos < 0 ||
2316            pos == ad->pos)
2317                return;
2318
2319        ad->pos = pos;
2320
2321        panel->applet_list =
2322                my_g_list_resort_item (panel->applet_list, ad,
2323                                       (GCompareFunc)applet_data_compare);
2324
2325        panel_widget_queue_applet_for_resize (ad);
2326}
2327
2328/* schedule to run the below function */
2329static void schedule_try_move (PanelWidget *panel, gboolean repeater);
2330
2331/*find the cursor position and move the applet to that position*/
2332static void
2333panel_widget_applet_move_to_cursor (PanelWidget *panel)
2334{
2335        int moveby;
2336        int pos;
2337        int movement;
2338        GtkWidget *applet;
2339        GSList *forb;
2340        GdkModifierType mods;
2341        AppletData *ad;
2342
2343        g_return_if_fail(panel!=NULL);
2344        g_return_if_fail(IS_PANEL_WIDGET(panel));
2345
2346        if (panel->currently_dragged_applet == NULL)
2347                return;
2348
2349        ad = panel->currently_dragged_applet;
2350
2351        pos = ad->pos;
2352
2353        applet = ad->applet;
2354        g_assert(GTK_IS_WIDGET(applet));
2355        forb = gtk_object_get_data(GTK_OBJECT(applet),
2356                                   PANEL_APPLET_FORBIDDEN_PANELS);
2357
2358        if(!panel_widget_is_cursor(panel,10)) {
2359                GSList *list;
2360
2361                for(list=panels;
2362                    list!=NULL;
2363                    list=g_slist_next(list)) {
2364                        PanelWidget *new_panel =
2365                                PANEL_WIDGET(list->data);
2366
2367                        if(panel != new_panel &&
2368                           panel_widget_is_cursor(new_panel,10) &&
2369                           (!g_slist_find(forb,new_panel))) {
2370                                pos = panel_widget_get_moveby (new_panel, 0,
2371                                                               ad->drag_off);
2372                                if (pos < 0)
2373                                        pos = 0;
2374                                panel_widget_applet_drag_end (panel);
2375                                /*disable reentrancy into this
2376                                  function*/
2377                                if (panel_widget_reparent (panel,
2378                                                           new_panel,
2379                                                           applet,
2380                                                           pos) == -1) {
2381                                        panel_widget_applet_drag_start
2382                                                (panel, applet, ad->drag_off);
2383                                        /*can't find a free pos
2384                                          so cancel the reparent*/
2385                                        continue;
2386                                }
2387                                panel_widget_applet_drag_start (new_panel,
2388                                                                applet,
2389                                                                ad->drag_off);
2390                                /* schedule a move, the thing might have
2391                                 * gone outside the cursor, thus we need to
2392                                 * schedule a move */
2393                                schedule_try_move(new_panel, TRUE);
2394                                return;
2395                        }
2396                }
2397        }
2398
2399        gdk_window_get_pointer(GTK_WIDGET(panel)->window,
2400                               NULL,NULL,&mods);
2401
2402        movement = pw_movement_type;
2403
2404        if (panel->packed) {
2405                movement = PANEL_SWITCH_MOVE;
2406        } else {
2407                if (mods & GDK_CONTROL_MASK)
2408                        movement = PANEL_SWITCH_MOVE;
2409                else if (mods & GDK_SHIFT_MASK)
2410                        movement = PANEL_PUSH_MOVE;
2411                else if (mods & GDK_MOD1_MASK)
2412                        movement = PANEL_FREE_MOVE;
2413        }
2414
2415        switch(movement) {
2416        case PANEL_SWITCH_MOVE:
2417                moveby = panel_widget_get_moveby (panel, pos, ad->drag_off);
2418                panel_widget_switch_move (panel, ad, moveby);
2419                break;
2420        case PANEL_FREE_MOVE:
2421                pos = panel_widget_get_free_spot (panel, ad);
2422                panel_widget_nice_move (panel, ad, pos);
2423                break;
2424        case PANEL_PUSH_MOVE:
2425                moveby = panel_widget_get_moveby (panel, pos, ad->drag_off);
2426                panel_widget_push_move (panel, ad, moveby);
2427                break;
2428        }
2429}
2430
2431static int
2432move_timeout_handler(gpointer data)
2433{
2434        PanelWidget *panel = data;
2435        g_return_val_if_fail(data!=NULL,FALSE);
2436        g_return_val_if_fail(IS_PANEL_WIDGET(data),FALSE);
2437
2438        if(been_moved &&
2439           panel->currently_dragged_applet) {
2440                panel_widget_applet_move_to_cursor(panel);
2441                been_moved = FALSE;
2442                return TRUE;
2443        }
2444        been_moved = FALSE;
2445
2446        if(panel->currently_dragged_applet && repeat_if_outside) {
2447                int x,y;
2448                int w,h;
2449                GtkWidget *widget;
2450
2451                widget = panel->currently_dragged_applet->applet;
2452
2453                gtk_widget_get_pointer(widget, &x, &y);
2454                w = widget->allocation.width;
2455                h = widget->allocation.height;
2456
2457                /* if NOT inside return TRUE, this means we will be
2458                 * kept inside the timeout until we hit the damn widget
2459                 * or the drag ends */
2460                if(!(x>=0 && x<=w && y>=0 && y<=h))
2461                        return TRUE;
2462        }
2463
2464        moving_timeout = 0;
2465       
2466        return FALSE;
2467}
2468
2469static void
2470schedule_try_move(PanelWidget *panel, gboolean repeater)
2471{
2472        if (!panel->currently_dragged_applet)
2473                return;
2474        repeat_if_outside = repeater;
2475        if(moving_timeout == 0) {
2476                been_moved = FALSE;
2477                panel_widget_applet_move_to_cursor(panel);
2478                moving_timeout =
2479                        gtk_timeout_add (50, move_timeout_handler, panel);
2480        } else
2481                been_moved = TRUE;
2482}
2483
2484static gboolean
2485panel_widget_applet_event(GtkWidget *widget, GdkEvent *event, gpointer data)
2486{
2487        PanelWidget *panel;
2488        GdkEventButton *bevent;
2489
2490        g_return_val_if_fail(widget!=NULL,FALSE);
2491        g_return_val_if_fail(GTK_IS_WIDGET(widget),FALSE);
2492        g_return_val_if_fail(widget->parent!=NULL,FALSE);
2493        g_return_val_if_fail(IS_PANEL_WIDGET(widget->parent),FALSE);
2494        g_return_val_if_fail(event!=NULL,FALSE);
2495
2496        panel = PANEL_WIDGET(widget->parent);
2497
2498        g_return_val_if_fail(panel!=NULL,TRUE);
2499       
2500        switch (event->type) {
2501                case GDK_BUTTON_PRESS:
2502                        bevent = (GdkEventButton *) event;
2503#ifdef PANEL_DEBUG
2504                        printf("the appwidget %lX\n",(long)widget);
2505#endif
2506
2507                        /* don't propagate this event */
2508                        if (panel->currently_dragged_applet) {
2509                                gtk_signal_emit_stop_by_name
2510                                        (GTK_OBJECT (widget), "event");
2511                                return TRUE;
2512                        }
2513
2514                        if ( ! commie_mode &&
2515                            bevent->button == 2) {
2516                                /* Start drag */
2517                                panel_widget_applet_drag_start
2518                                        (panel, widget, PW_DRAG_OFF_CURSOR);
2519                                return TRUE;
2520                        }
2521
2522                        break;
2523
2524                case GDK_BUTTON_RELEASE:
2525                        if (panel->currently_dragged_applet) {
2526                                gtk_signal_emit_stop_by_name
2527                                        (GTK_OBJECT (widget), "event");
2528                                panel_widget_applet_drag_end(panel);
2529                                return TRUE;
2530                        }
2531
2532                        break;
2533                case GDK_MOTION_NOTIFY:
2534                        schedule_try_move(panel, FALSE);
2535                        break;
2536                default:
2537                        break;
2538        }
2539
2540        return FALSE;
2541}
2542
2543static int
2544panel_sub_event_handler(GtkWidget *widget, GdkEvent *event, gpointer data)
2545{
2546        g_return_val_if_fail(widget!=NULL,FALSE);
2547        g_return_val_if_fail(GTK_IS_WIDGET(widget),FALSE);
2548        g_return_val_if_fail(event!=NULL,FALSE);
2549
2550        switch (event->type) {
2551                GdkEventButton *bevent;
2552                /*pass these to the parent!*/
2553                case GDK_BUTTON_PRESS:
2554                case GDK_BUTTON_RELEASE:
2555                case GDK_MOTION_NOTIFY:
2556                        bevent = (GdkEventButton *)event;
2557                        if(bevent->button != 1 || panel_applet_in_drag)
2558                                return gtk_widget_event(data, event);
2559
2560                        break;
2561
2562                default:
2563                        break;
2564        }
2565
2566        return FALSE;
2567}
2568
2569
2570static void
2571bind_applet_events(GtkWidget *widget, gpointer data)
2572{
2573        g_return_if_fail(widget!=NULL);
2574        g_return_if_fail(GTK_IS_WIDGET(widget));
2575
2576        /* XXX: This is more or less a hack.  We need to be able to
2577         * capture events over applets so that we can drag them with
2578         * the mouse and such.  So we need to force the applet's
2579         * widgets to recursively send the events back to their parent
2580         * until the event gets to the applet wrapper (the
2581         * GtkEventBox) for processing by us.
2582         */
2583       
2584        if (!GTK_WIDGET_NO_WINDOW(widget))
2585                gtk_signal_connect(GTK_OBJECT(widget), "event",
2586                                   (GtkSignalFunc) panel_sub_event_handler,
2587                                   data);
2588       
2589        if (GTK_IS_CONTAINER(widget))
2590                gtk_container_foreach (GTK_CONTAINER (widget),
2591                                       bind_applet_events, data);
2592}
2593
2594static void
2595panel_widget_applet_destroy (GtkWidget *applet, gpointer data)
2596{
2597        AppletData *ad;
2598
2599        g_return_if_fail (applet != NULL);
2600        g_return_if_fail (GTK_IS_WIDGET (applet));
2601
2602        ad = gtk_object_get_data (GTK_OBJECT (applet), PANEL_APPLET_DATA);
2603
2604        /*if it wasn't yet removed*/
2605        if(applet->parent) {
2606                PanelWidget *panel = PANEL_WIDGET (applet->parent);
2607
2608                gtk_signal_emit (GTK_OBJECT (panel),
2609                                 panel_widget_signals[APPLET_ABOUT_TO_DIE_SIGNAL],
2610                                 applet);
2611
2612                if (panel->currently_dragged_applet == ad)
2613                        panel_widget_applet_drag_end (panel);
2614
2615                panel->applet_list = g_list_remove (panel->applet_list,ad);
2616                panel->no_window_applet_list =
2617                        g_list_remove (panel->no_window_applet_list, ad);
2618
2619        }
2620
2621        g_free (ad);
2622}
2623
2624
2625static void
2626bind_top_applet_events(GtkWidget *widget, gboolean bind_lower)
2627{
2628        g_return_if_fail(widget!=NULL);
2629        g_return_if_fail(GTK_IS_WIDGET(widget));
2630
2631        gtk_signal_connect(GTK_OBJECT(widget), "destroy",
2632                           GTK_SIGNAL_FUNC(panel_widget_applet_destroy),
2633                           NULL);
2634
2635        gtk_signal_connect(GTK_OBJECT(widget),
2636                           "event",
2637                           GTK_SIGNAL_FUNC(panel_widget_applet_event),
2638                           NULL);
2639
2640        /* XXX: This is more or less a hack.  We need to be able to
2641         * capture events over applets so that we can drag them with
2642         * the mouse and such.  So we need to force the applet's
2643         * widgets to recursively send the events back to their parent
2644         * until the event gets to the applet wrapper (the
2645         * GtkEventBox) for processing by us.
2646         */
2647
2648        if (bind_lower && GTK_IS_CONTAINER(widget))
2649                gtk_container_foreach (GTK_CONTAINER (widget),
2650                                       bind_applet_events, widget);
2651}
2652
2653static int
2654panel_widget_find_empty_pos(PanelWidget *panel, int pos)
2655{
2656        int i;
2657        int right=-1,left=-1;
2658        GList *list;
2659
2660        g_return_val_if_fail(panel!=NULL,-1);
2661        g_return_val_if_fail(IS_PANEL_WIDGET(panel),-1);
2662        g_return_val_if_fail(pos>=0,-1);
2663
2664        if(pos>=panel->size)
2665                pos = panel->size-1;
2666
2667        if(!panel->applet_list)
2668                return pos;
2669
2670        list = panel->applet_list;
2671
2672        for (i = pos; i < panel->size; i++) {
2673                list = walk_up_to (i, list);
2674                if ( ! is_in_applet (i, list->data)) {
2675                        right = i;
2676                        break;
2677                }
2678        }
2679
2680        for(i = pos;
2681            i >= (panel->no_padding_on_ends ? 0 : pw_applet_padding);
2682            i--) {
2683                list = walk_up_to (i, list);
2684                if ( ! is_in_applet (i, list->data)) {
2685                        left = i;
2686                        break;
2687                }
2688        }
2689
2690        if (left == -1) {
2691                if (right == -1)
2692                        return -1;
2693                else
2694                        return right;
2695        } else {
2696                if (right == -1)
2697                        return left;
2698                else
2699                        return abs (left - pos) > abs (right - pos) ?
2700                                right : left;
2701        }
2702}
2703
2704void
2705panel_widget_add_forbidden (PanelWidget *panel)
2706{
2707        g_return_if_fail (panel != NULL);
2708        g_return_if_fail (IS_PANEL_WIDGET (panel));
2709
2710        add_panel_to_forbidden (panel, panel);
2711}
2712
2713int
2714panel_widget_add_full (PanelWidget *panel, GtkWidget *applet, int pos,
2715                       gboolean bind_lower_events, gboolean insert_at_pos)
2716{
2717        AppletData *ad = NULL;
2718
2719        g_return_val_if_fail (panel != NULL, -1);
2720        g_return_val_if_fail (IS_PANEL_WIDGET (panel), -1);
2721        g_return_val_if_fail (applet != NULL, -1);
2722        g_return_val_if_fail (GTK_IS_WIDGET (applet), -1);
2723        g_return_val_if_fail (pos >= 0, -1);
2724       
2725        ad = gtk_object_get_data (GTK_OBJECT (applet), PANEL_APPLET_DATA);
2726
2727        if (ad != NULL)
2728                pos = ad->pos;
2729
2730        if (pos < 0)
2731                pos = 0;
2732        if ( ! panel->no_padding_on_ends &&
2733             pos < pw_applet_padding)
2734                pos = pw_applet_padding;
2735       
2736        if ( ! insert_at_pos) {
2737                if (panel->packed) {
2738                        if (get_applet_list_pos (panel, pos))
2739                                /*this is a slight hack so that this applet
2740                                  is inserted AFTER an applet with this pos
2741                                  number*/
2742                                pos++;
2743                } else {
2744                        int newpos = panel_widget_find_empty_pos (panel, pos);
2745                        if (newpos >= 0)
2746                                pos = newpos;
2747                        else if (get_applet_list_pos (panel, pos))
2748                                /*this is a slight hack so that this applet
2749                                  is inserted AFTER an applet with this pos
2750                                  number*/
2751                                pos++;
2752                }
2753        }
2754
2755        if(pos==-1) return -1;
2756
2757        if (ad == NULL) {
2758                ad = g_new (AppletData, 1);
2759                ad->applet = applet;
2760                ad->cells = 1;
2761                ad->pos = pos;
2762                ad->drag_off = 0;
2763                ad->dirty = FALSE;
2764                ad->no_die = 0;
2765                gtk_object_set_data (GTK_OBJECT (applet),
2766                                     PANEL_APPLET_DATA, ad);
2767               
2768                /*this is a completely new applet, which was not yet bound*/
2769                bind_top_applet_events (applet, bind_lower_events);
2770        }
2771
2772        panel->applet_list =
2773                g_list_insert_sorted(panel->applet_list,ad,
2774                                     (GCompareFunc)applet_data_compare);
2775        if(GTK_WIDGET_NO_WINDOW(applet))
2776                panel->no_window_applet_list =
2777                        g_list_prepend(panel->no_window_applet_list,ad);
2778
2779        /*this will get done right on size allocate!*/
2780        if(panel->orient == PANEL_HORIZONTAL)
2781                gtk_fixed_put(GTK_FIXED(panel),applet,
2782                              pos,0);
2783        else
2784                gtk_fixed_put(GTK_FIXED(panel),applet,
2785                              0,pos);
2786
2787
2788        gtk_widget_queue_resize(GTK_WIDGET(panel));
2789
2790        gtk_signal_emit(GTK_OBJECT(panel),
2791                        panel_widget_signals[APPLET_ADDED_SIGNAL],
2792                        applet);
2793       
2794        /*NOTE: forbidden list is not updated on addition, use the
2795        function above for the panel*/
2796
2797        return pos;
2798}
2799
2800gboolean
2801panel_widget_reparent (PanelWidget *old_panel,
2802                       PanelWidget *new_panel,
2803                       GtkWidget *applet,
2804                       int pos)
2805{
2806        AppletData *ad;
2807
2808        g_return_val_if_fail(old_panel!=NULL,-1);
2809        g_return_val_if_fail(IS_PANEL_WIDGET(old_panel),-1);
2810        g_return_val_if_fail(new_panel!=NULL,-1);
2811        g_return_val_if_fail(IS_PANEL_WIDGET(new_panel),-1);
2812        g_return_val_if_fail(applet!=NULL,-1);
2813        g_return_val_if_fail(GTK_IS_WIDGET(applet),-1);
2814        g_return_val_if_fail(pos>=0,-1);
2815
2816        ad = gtk_object_get_data(GTK_OBJECT(applet), PANEL_APPLET_DATA);
2817        g_return_val_if_fail(ad!=NULL,-1);
2818       
2819        /*we'll resize both panels anyway*/
2820        ad->dirty = FALSE;
2821       
2822        ad->pos = pos;
2823
2824        ad->no_die++;
2825
2826        /*reparent applet*/
2827        if (IS_BUTTON_WIDGET (applet)) {
2828                ButtonWidget *button = BUTTON_WIDGET(applet);
2829                if (button->cache != NULL)
2830                        gdk_pixmap_unref (button->cache);
2831                button->cache = NULL;
2832                gtk_widget_ref (applet);
2833                gtk_container_remove (GTK_CONTAINER (applet->parent), applet);
2834                gtk_container_add (GTK_CONTAINER (new_panel), applet);
2835                gtk_widget_unref (applet);
2836        } else
2837                gtk_widget_reparent (applet, GTK_WIDGET (new_panel));
2838
2839        gdk_flush();
2840
2841        ad->no_die--;
2842
2843        return pos;
2844}
2845
2846int
2847panel_widget_move (PanelWidget *panel, GtkWidget *applet, int pos)
2848{
2849        AppletData *ad;
2850
2851        g_return_val_if_fail(panel!=NULL,-1);
2852        g_return_val_if_fail(IS_PANEL_WIDGET(panel),-1);
2853        g_return_val_if_fail(applet!=NULL,-1);
2854        g_return_val_if_fail(GTK_IS_WIDGET(applet),-1);
2855        g_return_val_if_fail(pos>=0,-1);
2856
2857        ad = gtk_object_get_data(GTK_OBJECT(applet), PANEL_APPLET_DATA);
2858        ad->pos = -1;
2859        panel->applet_list = g_list_remove (panel->applet_list, ad);
2860        panel->no_window_applet_list =
2861                g_list_remove (panel->no_window_applet_list, ad);
2862       
2863        if(pos < 0)
2864                pos = 0;
2865        if(!panel->no_padding_on_ends && pos < pw_applet_padding)
2866                pos = pw_applet_padding;
2867
2868        if(get_applet_list_pos(panel,pos))
2869                /*this is a slight hack so that this applet is
2870                  inserted AFTER an applet with this pos number*/
2871                pos++;
2872        if(pos==-1) return -1;
2873
2874        ad->pos = pos;
2875        /*reset size to 1*/
2876        ad->cells = 1;
2877        panel->applet_list =
2878                g_list_insert_sorted(panel->applet_list,ad,
2879                                     (GCompareFunc)applet_data_compare);
2880        if(GTK_WIDGET_NO_WINDOW(ad->applet))
2881                panel->no_window_applet_list =
2882                        g_list_remove(panel->no_window_applet_list,ad);
2883
2884        gtk_signal_emit(GTK_OBJECT(panel),
2885                        panel_widget_signals[APPLET_MOVE_SIGNAL],
2886                        ad->applet);
2887        gtk_widget_queue_resize(GTK_WIDGET(panel));
2888
2889        return pos;
2890}
2891
2892int
2893panel_widget_get_pos(PanelWidget *panel, GtkWidget *applet)
2894{
2895        AppletData *ad;
2896
2897        g_return_val_if_fail(panel!=NULL,-1);
2898        g_return_val_if_fail(IS_PANEL_WIDGET(panel),-1);
2899        g_return_val_if_fail(applet!=NULL,-1);
2900        g_return_val_if_fail(GTK_IS_WIDGET(applet),-1);
2901
2902        ad = gtk_object_get_data(GTK_OBJECT(applet), PANEL_APPLET_DATA);
2903
2904        g_return_val_if_fail(ad,-1);
2905
2906        if(panel != PANEL_WIDGET(applet->parent))
2907                return -1;
2908
2909        return ad->pos;
2910}
2911
2912void
2913panel_widget_change_params(PanelWidget *panel,
2914                           PanelOrientation orient,
2915                           int sz,
2916                           PanelBackType back_type,
2917                           char *pixmap,
2918                           gboolean fit_pixmap_bg,
2919                           gboolean strech_pixmap_bg,
2920                           gboolean rotate_pixmap_bg,
2921                           gboolean no_padding_on_ends,
2922                           GdkColor *back_color)
2923{
2924        PanelOrientation oldorient;
2925        int oldsz;
2926        gboolean change_back = FALSE;
2927
2928        g_return_if_fail(panel!=NULL);
2929        g_return_if_fail(IS_PANEL_WIDGET(panel));
2930        g_return_if_fail(GTK_WIDGET_REALIZED(panel));
2931
2932        oldorient = panel->orient;
2933        panel->orient = orient;
2934
2935        oldsz = panel->sz;
2936        panel->sz = sz;
2937       
2938#ifdef PANEL_DEBUG
2939        printf("GOT SIZE OF %d\n",sz);
2940#endif
2941
2942        kill_cache_on_all_buttons(panel, TRUE);
2943        send_draw_to_all_applets(panel);
2944
2945        if(oldorient != panel->orient) {
2946                gtk_signal_emit(GTK_OBJECT(panel),
2947                                panel_widget_signals[ORIENT_CHANGE_SIGNAL],
2948                                panel->orient);
2949        }
2950        if(oldsz != panel->sz) {
2951                gtk_signal_emit(GTK_OBJECT(panel),
2952                                panel_widget_signals[SIZE_CHANGE_SIGNAL],
2953                                panel->sz);
2954        }
2955        if(back_color) {
2956                /*this will allways trigger, but so what*/
2957                if(back_type == PANEL_BACK_COLOR)
2958                        change_back = TRUE;
2959                panel->back_color = *back_color;
2960        } /*if we didn't pass a color, then don't set a new color!*/
2961
2962        /*only change the pixmap name if we passed a non-null value*/
2963        if(pixmap && pixmap != panel->back_pixmap) {
2964                if(back_type == PANEL_BACK_PIXMAP)
2965                        change_back = TRUE;
2966
2967                g_free (panel->back_pixmap);
2968                panel->back_pixmap = g_strdup (pixmap);
2969        }
2970
2971        /*clearly a signal should be sent*/
2972        if(panel->back_type != back_type ||
2973           panel->fit_pixmap_bg != fit_pixmap_bg ||
2974           panel->strech_pixmap_bg != strech_pixmap_bg ||
2975           panel->rotate_pixmap_bg != rotate_pixmap_bg)
2976                change_back = TRUE;
2977       
2978        /*this bit is not optimal, it allways sets the pixmap etc etc ...
2979          but this function isn't called too often*/
2980        panel->back_type = back_type;
2981        panel->fit_pixmap_bg = fit_pixmap_bg;
2982        panel->strech_pixmap_bg = strech_pixmap_bg;
2983        panel->rotate_pixmap_bg = rotate_pixmap_bg;
2984        if(back_type == PANEL_BACK_PIXMAP) {
2985                panel_try_to_set_pixmap (panel, panel->back_pixmap);
2986                /* we will queue resize and redraw anyhow */
2987        } else if(back_type == PANEL_BACK_COLOR) {
2988                panel_try_to_set_back_color(panel, &panel->back_color);
2989        } else if(back_type == PANEL_BACK_TRANSLUCENT) {
2990                panel_try_to_set_translucent (panel);
2991        }
2992
2993        /* let the applets know we changed the background */
2994        if (change_back) {
2995                gtk_signal_emit (GTK_OBJECT (panel),
2996                                 panel_widget_signals[BACK_CHANGE_SIGNAL],
2997                                 panel->back_type,
2998                                 panel->back_pixmap,
2999                                 &panel->back_color);
3000        }
3001
3002        panel->no_padding_on_ends = no_padding_on_ends;
3003
3004        /* inhibit draws until we resize */
3005        panel->inhibit_draw = TRUE;
3006        gtk_widget_queue_resize (GTK_WIDGET (panel));
3007}
3008
3009void
3010panel_widget_change_orient(PanelWidget *panel,
3011                           PanelOrientation orient)
3012{
3013        panel_widget_change_params(panel,
3014                                   orient,
3015                                   panel->sz,
3016                                   panel->back_type,
3017                                   panel->back_pixmap,
3018                                   panel->fit_pixmap_bg,
3019                                   panel->strech_pixmap_bg,
3020                                   panel->rotate_pixmap_bg,
3021                                   panel->no_padding_on_ends,
3022                                   &panel->back_color);
3023}
3024
3025
3026/*change global params*/
3027void
3028panel_widget_change_global (int explicit_step,
3029                            int auto_step,
3030                            int drawer_step,
3031                            int minimized_size,
3032                            int minimize_delay,
3033                            int maximize_delay,
3034                            PanelMovementType move_type,
3035                            gboolean disable_animations,
3036                            int applet_padding,
3037                            int applet_border_padding)
3038{
3039        if (explicit_step > 0)
3040                pw_explicit_step=explicit_step;
3041        if (auto_step > 0)
3042                pw_auto_step=auto_step;
3043        if (drawer_step > 0)
3044                pw_drawer_step=drawer_step;
3045        if (minimized_size > 0)
3046                pw_minimized_size=minimized_size;
3047        if (minimize_delay >= 0)
3048                pw_minimize_delay=minimize_delay;
3049        if (maximize_delay >= 0)
3050                pw_maximize_delay=maximize_delay;
3051        pw_movement_type = move_type;
3052        pw_disable_animations = disable_animations;
3053
3054        /*change padding on all panels NOW*/
3055        if( (pw_applet_padding != applet_padding) ||
3056            (pw_applet_border_padding != applet_border_padding)) {
3057                GSList *li;
3058                pw_applet_padding = applet_padding;
3059                pw_applet_border_padding = applet_border_padding;
3060                for (li = panels; li != NULL; li = li->next)
3061                        gtk_widget_queue_resize (li->data);
3062        }
3063}
3064
3065/* when we get color_only, we also optionally set r, g, b to the
3066   color and w, and h to the area if the background is one color
3067   only, otherwise normally return an rgb and set r, g, b to -1 */
3068void
3069panel_widget_get_applet_rgb_bg (PanelWidget *panel,
3070                                GtkWidget *applet,
3071                                guchar **rgb,
3072                                int *w, int *h,
3073                                int *rowstride,
3074                                gboolean color_only,
3075                                int *r, int *g, int *b)
3076{
3077        GtkWidget *widget;
3078
3079        GdkPixbuf *pb = NULL;
3080
3081        int scale_w = 0,scale_h = 0;
3082        int rotate = FALSE;
3083       
3084        *rgb = NULL;
3085        *w = *h = *rowstride = 0;
3086        *r = *g = *b = -1;
3087
3088        g_return_if_fail (panel != NULL);
3089        g_return_if_fail (IS_PANEL_WIDGET (panel));
3090        g_return_if_fail (applet != NULL);
3091        g_return_if_fail (GTK_IS_WIDGET (applet));
3092
3093        widget = GTK_WIDGET (panel);
3094
3095        if( ! GTK_WIDGET_DRAWABLE (widget) ||
3096           widget->allocation.width <= 0 ||
3097           widget->allocation.height <= 0)
3098                return;
3099
3100        setup_background (panel, &pb, &scale_w, &scale_h, &rotate);
3101       
3102        *w = applet->allocation.width;
3103        *h = applet->allocation.height;
3104       
3105        if (color_only &&
3106            pb == NULL) {
3107                if(panel->back_type != PANEL_BACK_COLOR) {
3108                        GtkWidget *widget = GTK_WIDGET(panel);
3109                        /* convert to 8 bit per channel */
3110                        *r = widget->style->bg[GTK_WIDGET_STATE(widget)].red>>8;
3111                        *g = widget->style->bg[GTK_WIDGET_STATE(widget)].green>>8;
3112                        *b = widget->style->bg[GTK_WIDGET_STATE(widget)].blue>>8;
3113                } else {
3114                        /* convert to 8 bit per channel */
3115                        *r = panel->back_color.red>>8;
3116                        *g = panel->back_color.green>>8;
3117                        *b = panel->back_color.blue>>8;
3118                }
3119                return;
3120        }
3121        *rowstride = applet->allocation.width * 3;
3122
3123        *rgb = g_new0(guchar,
3124                      (*h) * (*rowstride));
3125
3126        make_background (panel, *rgb,
3127                         applet->allocation.x,
3128                         applet->allocation.y,
3129                         *w, *h, pb, scale_w, scale_h, rotate);
3130}
Note: See TracBrowser for help on using the repository browser.