/* Gnome panel: panel widget * (C) 1997 the Free Software Foundation * * Authors: George Lebl */ #include #include #include #include #include #include "panel-widget.h" #include "button-widget.h" #include "panel-util.h" #include "gdkextra.h" GSList *panels=NULL; /*other panels we might want to move the applet to*/ /*define for some debug output*/ /*#define DEBUG 1*/ /*there can universally be only one applet being dragged since we assume we only have one mouse :) */ int panel_applet_in_drag = FALSE; static void panel_widget_class_init (PanelWidgetClass *klass); static void panel_widget_init (PanelWidget *panel_widget); static int panel_try_to_set_pixmap (PanelWidget *panel, char *pixmap); static void panel_resize_pixmap (PanelWidget *panel); static void panel_try_to_set_back_color (PanelWidget *panel, GdkColor *color); static void panel_widget_size_request (GtkWidget *widget, GtkRequisition *requisition); static void panel_widget_size_allocate (GtkWidget *widget, GtkAllocation *allocation); static void panel_widget_cadd (GtkContainer *container, GtkWidget *widget); static void panel_widget_cremove (GtkContainer *container, GtkWidget *widget); static int panel_widget_expose (GtkWidget *widget, GdkEventExpose *event); static void panel_widget_draw (GtkWidget *widget, GdkRectangle *area); /*global settings*/ int pw_explicit_step = 50; int pw_drawer_step = 20; int pw_auto_step = 10; int pw_minimized_size = 6; int pw_minimize_delay = 300; int pw_disable_animations = FALSE; PanelMovementType pw_movement_type = PANEL_SWITCH_MOVE; int pw_applet_padding = 3; #define APPLET_EVENT_MASK (GDK_BUTTON_PRESS_MASK | \ GDK_BUTTON_RELEASE_MASK | \ GDK_POINTER_MOTION_MASK | \ GDK_POINTER_MOTION_HINT_MASK) typedef void (*OrientSignal) (GtkObject * object, PanelOrientation orient, gpointer data); typedef void (*BackSignal) (GtkObject * object, PanelBackType type, char *pixmap, GdkColor *color, gpointer data); typedef void (*AppletSignal) (GtkObject * object, GtkWidget * applet, gpointer data); /************************ debugging ************************/ /*static void debug_dump_panel_list(PanelWidget *panel) { GList *list; puts("\nDUMP START\n"); for(list = panel->applet_list;list!=NULL;list=g_list_next(list)) { AppletData *ad = list->data; printf("pos: %d cells: %d\n",ad->pos,ad->cells); } puts("\nDUMP END\n"); }*/ /************************ convenience functions ************************/ static int applet_data_compare(AppletData *ad1, AppletData *ad2) { return ad1->pos - ad2->pos; } /************************ widget core ************************/ guint panel_widget_get_type () { static guint panel_widget_type = 0; if (!panel_widget_type) { GtkTypeInfo panel_widget_info = { "PanelWidget", sizeof (PanelWidget), sizeof (PanelWidgetClass), (GtkClassInitFunc) panel_widget_class_init, (GtkObjectInitFunc) panel_widget_init, (GtkArgSetFunc) NULL, (GtkArgGetFunc) NULL, }; panel_widget_type = gtk_type_unique (gtk_fixed_get_type (), &panel_widget_info); } return panel_widget_type; } enum { ORIENT_CHANGE_SIGNAL, APPLET_MOVE_SIGNAL, APPLET_ADDED_SIGNAL, APPLET_REMOVED_SIGNAL, BACK_CHANGE_SIGNAL, LAST_SIGNAL }; static int panel_widget_signals[LAST_SIGNAL] = {0,0,0,0,0}; static GtkFixedClass *parent_class = NULL; static void marshal_signal_orient (GtkObject * object, GtkSignalFunc func, gpointer func_data, GtkArg * args) { OrientSignal rfunc; rfunc = (OrientSignal) func; (*rfunc) (object, GTK_VALUE_ENUM (args[0]), func_data); } static void marshal_signal_applet (GtkObject * object, GtkSignalFunc func, gpointer func_data, GtkArg * args) { AppletSignal rfunc; rfunc = (AppletSignal) func; (*rfunc) (object, GTK_VALUE_POINTER (args[0]), func_data); } static void marshal_signal_back (GtkObject * object, GtkSignalFunc func, gpointer func_data, GtkArg * args) { BackSignal rfunc; rfunc = (BackSignal) func; (*rfunc) (object, GTK_VALUE_ENUM (args[0]), GTK_VALUE_POINTER (args[1]), GTK_VALUE_POINTER (args[2]), func_data); } static void panel_widget_class_init (PanelWidgetClass *class) { GtkObjectClass *object_class = (GtkObjectClass*) class; GtkWidgetClass *widget_class = (GtkWidgetClass*) class; GtkContainerClass *container_class = (GtkContainerClass*) class; parent_class = gtk_type_class (gtk_fixed_get_type ()); panel_widget_signals[ORIENT_CHANGE_SIGNAL] = gtk_signal_new("orient_change", GTK_RUN_LAST, object_class->type, GTK_SIGNAL_OFFSET(PanelWidgetClass, orient_change), marshal_signal_orient, GTK_TYPE_NONE, 1, GTK_TYPE_ENUM); panel_widget_signals[APPLET_MOVE_SIGNAL] = gtk_signal_new("applet_move", GTK_RUN_LAST, object_class->type, GTK_SIGNAL_OFFSET(PanelWidgetClass, applet_move), marshal_signal_applet, GTK_TYPE_NONE, 1, GTK_TYPE_POINTER); panel_widget_signals[APPLET_ADDED_SIGNAL] = gtk_signal_new("applet_added", GTK_RUN_LAST, object_class->type, GTK_SIGNAL_OFFSET(PanelWidgetClass, applet_added), marshal_signal_applet, GTK_TYPE_NONE, 1, GTK_TYPE_POINTER); panel_widget_signals[APPLET_REMOVED_SIGNAL] = gtk_signal_new("applet_removed", GTK_RUN_LAST, object_class->type, GTK_SIGNAL_OFFSET(PanelWidgetClass, applet_removed), marshal_signal_applet, GTK_TYPE_NONE, 1, GTK_TYPE_POINTER); panel_widget_signals[BACK_CHANGE_SIGNAL] = gtk_signal_new("back_change", GTK_RUN_LAST, object_class->type, GTK_SIGNAL_OFFSET(PanelWidgetClass, back_change), marshal_signal_back, GTK_TYPE_NONE, 3, GTK_TYPE_ENUM, GTK_TYPE_POINTER, GTK_TYPE_POINTER); gtk_object_class_add_signals(object_class,panel_widget_signals, LAST_SIGNAL); class->orient_change = NULL; class->applet_move = NULL; class->applet_added = NULL; class->applet_removed = NULL; class->back_change = NULL; widget_class->size_request = panel_widget_size_request; widget_class->size_allocate = panel_widget_size_allocate; widget_class->expose_event = panel_widget_expose; widget_class->draw = panel_widget_draw; container_class->add = panel_widget_cadd; container_class->remove = panel_widget_cremove; } static void remove_panel_from_forbidden(PanelWidget *panel, PanelWidget *r) { GSList *list; GtkWidget *parent_panel; g_return_if_fail(panel!=NULL); g_return_if_fail(IS_PANEL_WIDGET(panel)); g_return_if_fail(r!=NULL); g_return_if_fail(IS_PANEL_WIDGET(r)); if(!panel->master_widget) return; list = gtk_object_get_data(GTK_OBJECT(panel->master_widget), PANEL_APPLET_FORBIDDEN_PANELS); if(list) { list = g_slist_remove(list,r); gtk_object_set_data(GTK_OBJECT(panel->master_widget), PANEL_APPLET_FORBIDDEN_PANELS, list); } parent_panel = panel->master_widget->parent; if (parent_panel) remove_panel_from_forbidden(PANEL_WIDGET(parent_panel), r); } static void add_panel_to_forbidden(PanelWidget *panel, PanelWidget *r) { GSList *list; GtkWidget *parent_panel; g_return_if_fail(panel!=NULL); g_return_if_fail(IS_PANEL_WIDGET(panel)); g_return_if_fail(r!=NULL); g_return_if_fail(IS_PANEL_WIDGET(r)); if(!panel->master_widget) return; list = gtk_object_get_data(GTK_OBJECT(panel->master_widget), PANEL_APPLET_FORBIDDEN_PANELS); if(g_slist_find(list,r)==NULL) { list = g_slist_prepend(list,r); gtk_object_set_data(GTK_OBJECT(panel->master_widget), PANEL_APPLET_FORBIDDEN_PANELS, list); } parent_panel = panel->master_widget->parent; if (parent_panel) add_panel_to_forbidden(PANEL_WIDGET(parent_panel), r); } static void run_up_forbidden(PanelWidget *panel, void (*runfunc)(PanelWidget *,PanelWidget *)) { GList *list; g_return_if_fail(panel!=NULL); g_return_if_fail(IS_PANEL_WIDGET(panel)); for(list = panel->applet_list;list!=NULL;list = g_list_next(list)) { AppletData *ad = list->data; PanelWidget *p = gtk_object_get_data(GTK_OBJECT(ad->applet), PANEL_APPLET_ASSOC_PANEL_KEY); if(p) run_up_forbidden(p,runfunc); } (*runfunc)(panel,panel); } static void panel_widget_cadd(GtkContainer *container, GtkWidget *widget) { PanelWidget *p; g_return_if_fail (container != NULL); g_return_if_fail (IS_PANEL_WIDGET (container)); g_return_if_fail (widget != NULL); g_return_if_fail (GTK_IS_WIDGET (widget)); panel_widget_add(PANEL_WIDGET(container),widget,0); p = gtk_object_get_data(GTK_OBJECT(widget), PANEL_APPLET_ASSOC_PANEL_KEY); if(p) run_up_forbidden(p,add_panel_to_forbidden); } static void panel_widget_cremove(GtkContainer *container, GtkWidget *widget) { AppletData *ad; PanelWidget *p; PanelWidget *panel; g_return_if_fail (container != NULL); g_return_if_fail (IS_PANEL_WIDGET (container)); g_return_if_fail (widget != NULL); g_return_if_fail (GTK_IS_WIDGET (widget)); panel = PANEL_WIDGET (container); ad = gtk_object_get_data(GTK_OBJECT(widget), PANEL_APPLET_DATA); p = gtk_object_get_data(GTK_OBJECT(widget), PANEL_APPLET_ASSOC_PANEL_KEY); if(p) run_up_forbidden(p,remove_panel_from_forbidden); gtk_widget_ref(widget); if (GTK_CONTAINER_CLASS (parent_class)->remove) (* GTK_CONTAINER_CLASS (parent_class)->remove) (container, widget); if(ad) { PanelWidget *panel = PANEL_WIDGET (container); panel->applet_list = g_list_remove (panel->applet_list, ad); panel->no_window_applet_list = g_list_remove (panel->no_window_applet_list, ad); } gtk_signal_emit(GTK_OBJECT(container), panel_widget_signals[APPLET_REMOVED_SIGNAL], widget); gtk_widget_unref(widget); } /*get the number of applets*/ int panel_widget_get_applet_count(PanelWidget *panel) { g_return_val_if_fail(panel!=NULL,-1); g_return_val_if_fail(IS_PANEL_WIDGET(panel),-1); return g_list_length(GTK_FIXED(panel)->children); } /*get the list item of the data on the position pos*/ static GList * get_applet_list_pos(PanelWidget *panel, int pos) { GList *list; g_return_val_if_fail(panel!=NULL,NULL); g_return_val_if_fail(IS_PANEL_WIDGET(panel),NULL); for(list=panel->applet_list;list!=NULL;list=g_list_next(list)) { AppletData *ad = list->data; if(ad->pos <= pos) { if(ad->pos+ad->cells > pos) return list; } else return NULL; } return NULL; } /*tells us if an applet is "stuck" on the right side*/ int panel_widget_is_applet_stuck(PanelWidget *panel, GtkWidget *applet) { AppletData *ad; GList *list; int i; g_return_val_if_fail(panel!=NULL,FALSE); g_return_val_if_fail(IS_PANEL_WIDGET(panel),FALSE); g_return_val_if_fail(applet!=NULL,FALSE); g_return_val_if_fail(GTK_IS_WIDGET(applet),FALSE); ad = gtk_object_get_data(GTK_OBJECT(applet), PANEL_APPLET_DATA); g_return_val_if_fail(ad!=NULL,FALSE); list = g_list_find(panel->applet_list,ad); g_return_val_if_fail(list!=NULL,FALSE); do { i=ad->pos+ad->cells; if(i==panel->size) return TRUE; list = g_list_next(list); if(!list) break; ad = list->data; } while(ad->pos==i); return FALSE; } static void panel_widget_switch_applet_right(PanelWidget *panel, GList *list) { AppletData *ad; AppletData *nad; GList *nlist; g_return_if_fail(panel!=NULL); g_return_if_fail(IS_PANEL_WIDGET(panel)); g_return_if_fail(list!=NULL); ad = list->data; nlist = g_list_next(list); if(nlist) nad = nlist->data; if(!nlist || nad->pos > ad->pos+ad->cells) { ad->pos++; gtk_widget_queue_resize(GTK_WIDGET(panel)); return; } nad->pos = ad->pos; ad->pos = nad->pos+nad->cells; panel->applet_list = my_g_list_swap_prev(panel->applet_list,nlist); gtk_signal_emit(GTK_OBJECT(panel), panel_widget_signals[APPLET_MOVE_SIGNAL], ad->applet); gtk_signal_emit(GTK_OBJECT(panel), panel_widget_signals[APPLET_MOVE_SIGNAL], nad->applet); gtk_widget_queue_resize(GTK_WIDGET(panel)); } static void panel_widget_switch_applet_left(PanelWidget *panel, GList *list) { AppletData *ad; AppletData *pad; GList *nlist; g_return_if_fail(panel!=NULL); g_return_if_fail(IS_PANEL_WIDGET(panel)); g_return_if_fail(list!=NULL); ad = list->data; nlist = g_list_previous(list); if(nlist) pad = nlist->data; if(!nlist || pad->pos+pad->cells < ad->pos) { ad->pos--; gtk_widget_queue_resize(GTK_WIDGET(panel)); return; } ad->pos = pad->pos; pad->pos = ad->pos+ad->cells; panel->applet_list = my_g_list_swap_next(panel->applet_list,nlist); gtk_signal_emit(GTK_OBJECT(panel), panel_widget_signals[APPLET_MOVE_SIGNAL], ad->applet); gtk_signal_emit(GTK_OBJECT(panel), panel_widget_signals[APPLET_MOVE_SIGNAL], pad->applet); gtk_widget_queue_resize(GTK_WIDGET(panel)); } static int panel_widget_get_right_switch_pos(PanelWidget *panel, GList *list) { AppletData *ad; AppletData *nad; g_return_val_if_fail(panel!=NULL,-1); g_return_val_if_fail(IS_PANEL_WIDGET(panel),-1); g_return_val_if_fail(list!=NULL,-1); ad = list->data; list = g_list_next(list); if(list) nad = list->data; if(!list || nad->pos > ad->pos+ad->cells) return ad->pos+1; return nad->pos+nad->cells-ad->cells; } static int panel_widget_get_left_switch_pos(PanelWidget *panel, GList *list) { AppletData *ad; AppletData *pad; g_return_val_if_fail(panel!=NULL,-1); g_return_val_if_fail(IS_PANEL_WIDGET(panel),-1); g_return_val_if_fail(list!=NULL,-1); ad = list->data; list = g_list_previous(list); if(list) pad = list->data; if(!list || pad->pos+pad->cells < ad->pos) return ad->pos-1; return pad->pos; } static void panel_widget_switch_move(PanelWidget *panel, AppletData *ad, int moveby) { int finalpos; int pos; GList *list; g_return_if_fail(ad!=NULL); g_return_if_fail(panel!=NULL); g_return_if_fail(IS_PANEL_WIDGET(panel)); if(moveby==0) return; list = g_list_find(panel->applet_list,ad); g_return_if_fail(list!=NULL); finalpos = ad->pos+moveby; if(finalpos >= panel->size) finalpos = panel->size-1; else if(finalpos < pw_applet_padding) finalpos = pw_applet_padding; while((ad->pos+ad->cells-1) finalpos || pos+ad->cells-1 >= panel->size) return; panel_widget_switch_applet_right(panel,list); } while(ad->pos>finalpos) { if((panel_widget_get_left_switch_pos(panel,list)+ad->cells-1) < finalpos) return; panel_widget_switch_applet_left(panel,list); } return; } /*this is a special function and may fail if called improperly, it works only under special circumstance when we know there is nothing from old_size to panel->size*/ static void panel_widget_right_stick(PanelWidget *panel,int old_size) { int i,pos; GList *list,*prev; AppletData *ad; g_return_if_fail(panel!=NULL); g_return_if_fail(IS_PANEL_WIDGET(panel)); g_return_if_fail(old_size>=0); if(old_size>=panel->size || panel->packed) return; list = get_applet_list_pos(panel,old_size-1); if(!list) return; pos = panel->size-1; ad = list->data; do { i = ad->pos; ad->pos = pos--; ad->cells = 1; prev = list; list = g_list_previous(list); if(!list) break; ad = list->data; } while(ad->pos+ad->cells == i); for(list = prev;list!=NULL;list=g_list_next(list)) gtk_signal_emit(GTK_OBJECT(panel), panel_widget_signals[APPLET_MOVE_SIGNAL], ((AppletData *)list->data)->applet); } static void panel_widget_size_request(GtkWidget *widget, GtkRequisition *requisition) { PanelWidget *panel; GList *list; g_return_if_fail(widget!=NULL); g_return_if_fail(IS_PANEL_WIDGET(widget)); g_return_if_fail(requisition!=NULL); panel = PANEL_WIDGET(widget); if(panel->orient == PANEL_HORIZONTAL) { requisition->width = pw_applet_padding; requisition->height = PANEL_MINIMUM_WIDTH; } else { requisition->height = pw_applet_padding; requisition->width = PANEL_MINIMUM_WIDTH; } for(list = panel->applet_list; list!=NULL; list = g_list_next(list)) { AppletData *ad = list->data; GtkRequisition chreq; gtk_widget_size_request(ad->applet,&chreq); if(panel->orient == PANEL_HORIZONTAL) { if(requisition->height < chreq.height) requisition->height = chreq.height; if(panel->packed) requisition->width += chreq.width + pw_applet_padding; } else { if(requisition->width < chreq.width) requisition->width = chreq.width; if(panel->packed) requisition->height += chreq.height + pw_applet_padding; } } if(!panel->packed) { if(panel->orient == PANEL_HORIZONTAL) { requisition->width = panel->size; } else { requisition->height = panel->size; } } } void panel_widget_draw_all(PanelWidget *panel) { GList *li; GtkWidget *widget; GdkGC *gc; g_return_if_fail(panel!=NULL); g_return_if_fail(IS_PANEL_WIDGET(panel)); if(!panel->pixmap) /*it will get drawn soon anyhow*/ return; widget = GTK_WIDGET(panel); gc = widget->style->bg_gc[GTK_WIDGET_STATE(widget)]; if(widget->style->bg_pixmap[GTK_WIDGET_STATE(widget)]) { gdk_gc_set_fill(gc, GDK_TILED); gdk_gc_set_tile(gc, widget->style->bg_pixmap[GTK_WIDGET_STATE(widget)]); } gdk_draw_rectangle(panel->pixmap,gc, TRUE, 0,0,-1,-1); gdk_gc_set_fill(gc, GDK_SOLID); /* gdk_gc_set_tile(gc, NULL); */ for(li = panel->applet_list; li != NULL; li = g_list_next(li)) { AppletData *ad = li->data; if(IS_BUTTON_WIDGET(ad->applet)) button_widget_draw(BUTTON_WIDGET(ad->applet), panel->pixmap); } if(GTK_WIDGET_DRAWABLE(widget)) gdk_draw_pixmap(widget->window, widget->style->fg_gc[GTK_WIDGET_STATE(widget)], panel->pixmap, 0,0,0,0,-1,-1); } void panel_widget_draw_icon(PanelWidget *panel, ButtonWidget *button) { GtkWidget *widget; GtkWidget *applet; GdkGC *gc; g_return_if_fail(panel!=NULL); g_return_if_fail(IS_PANEL_WIDGET(panel)); g_return_if_fail(button != NULL); g_return_if_fail(IS_BUTTON_WIDGET(button)); if(!panel->pixmap) /*it will get drawn soon anyhow*/ return; widget = GTK_WIDGET(panel); applet = GTK_WIDGET(button); gc = widget->style->bg_gc[GTK_WIDGET_STATE(widget)]; if(widget->style->bg_pixmap[GTK_WIDGET_STATE(widget)]) { gdk_gc_set_fill(gc, GDK_TILED); gdk_gc_set_tile(gc, widget->style->bg_pixmap[GTK_WIDGET_STATE(widget)]); } gdk_draw_rectangle(panel->pixmap,gc, TRUE, applet->allocation.x,applet->allocation.y, applet->allocation.width,applet->allocation.height); gdk_gc_set_fill(gc, GDK_SOLID); /* gdk_gc_set_tile(gc, NULL); */ button_widget_draw(button, panel->pixmap); if(GTK_WIDGET_DRAWABLE(widget)) gdk_draw_pixmap(widget->window, widget->style->fg_gc[GTK_WIDGET_STATE(widget)], panel->pixmap, applet->allocation.x,applet->allocation.y, applet->allocation.x,applet->allocation.y, applet->allocation.width,applet->allocation.height); } static void panel_widget_draw(GtkWidget *widget, GdkRectangle *area) { GList *li; PanelWidget *panel; g_return_if_fail(widget!=NULL); g_return_if_fail(IS_PANEL_WIDGET(widget)); panel = PANEL_WIDGET(widget); if(!GTK_WIDGET_DRAWABLE(widget)) return; if(panel->pixmap) { gdk_draw_pixmap(widget->window, widget->style->fg_gc[GTK_WIDGET_STATE(widget)], panel->pixmap, area->x, area->y, area->x, area->y, area->width, area->height); } for(li = panel->applet_list; li != NULL; li = g_list_next(li)) { AppletData *ad = li->data; GdkRectangle ch_area; if(!IS_BUTTON_WIDGET(ad->applet) && gtk_widget_intersect(ad->applet, area, &ch_area)) gtk_widget_draw(ad->applet, &ch_area); } } static int panel_widget_expose(GtkWidget *widget, GdkEventExpose *event) { GList *li; PanelWidget *panel; g_return_val_if_fail(widget!=NULL,FALSE); g_return_val_if_fail(IS_PANEL_WIDGET(widget),FALSE); g_return_val_if_fail(event!=NULL,FALSE); panel = PANEL_WIDGET(widget); if(!GTK_WIDGET_DRAWABLE(widget)) return FALSE; if(panel->pixmap) { gdk_draw_pixmap(widget->window, widget->style->fg_gc[GTK_WIDGET_STATE(widget)], panel->pixmap, event->area.x, event->area.y, event->area.x, event->area.y, event->area.width, event->area.height); } for(li = panel->applet_list; li != NULL; li = g_list_next(li)) { AppletData *ad = li->data; GdkEventExpose ch_event = *event; if(!IS_BUTTON_WIDGET(ad->applet) && GTK_WIDGET_NO_WINDOW (ad->applet) && gtk_widget_intersect (ad->applet, &event->area, &ch_event.area)) gtk_widget_event (ad->applet, (GdkEvent*) &ch_event); } return FALSE; } static int fit_pix_timeout(gpointer data) { PanelWidget *panel = data; if(panel->pixmap_resize_pending && panel->fit_pixmap_bg && panel->back_type == PANEL_BACK_PIXMAP) { panel_resize_pixmap(panel); panel->pixmap_resize_pending = FALSE; return TRUE; } panel->pixmap_resize_timeout = 0; panel->pixmap_resize_pending = FALSE; return FALSE; } static int fit_pix_timeout_top(gpointer data) { PanelWidget *panel = data; if(panel->pixmap_resize_timeout || !panel->fit_pixmap_bg || panel->back_type != PANEL_BACK_PIXMAP) return FALSE; panel_resize_pixmap(panel); panel->pixmap_resize_pending = FALSE; panel->pixmap_resize_timeout = gtk_timeout_add(2000,fit_pix_timeout,panel); return FALSE; } static void panel_widget_size_allocate(GtkWidget *widget, GtkAllocation *allocation) { PanelWidget *panel; GList *list; GSList *send_move = NULL; GSList *li; int i; int old_size; int old_thick; g_return_if_fail(widget!=NULL); g_return_if_fail(IS_PANEL_WIDGET(widget)); g_return_if_fail(allocation!=NULL); panel = PANEL_WIDGET(widget); old_size = panel->size; old_thick = panel->thick; widget->allocation = *allocation; if (GTK_WIDGET_REALIZED (widget)) gdk_window_move_resize (widget->window, allocation->x, allocation->y, allocation->width, allocation->height); if(panel->orient == PANEL_HORIZONTAL) panel->size = allocation->width; else panel->size = allocation->height; if(old_sizesize) panel_widget_right_stick(panel,old_size); if(panel->packed) { i = pw_applet_padding; for(list = panel->applet_list; list!=NULL; list = g_list_next(list)) { AppletData *ad = list->data; GtkAllocation challoc; GtkRequisition chreq; gtk_widget_get_child_requisition(ad->applet,&chreq); if(i != ad->pos) { ad->pos = i; send_move = g_slist_prepend(send_move,ad); } if(panel->orient == PANEL_HORIZONTAL) { ad->cells = chreq.width + pw_applet_padding; challoc.x = ad->pos; challoc.y = (allocation->height - chreq.height) / 2; } else { ad->cells = chreq.height + pw_applet_padding; challoc.x = (allocation->width - chreq.width) / 2; challoc.y = ad->pos; } challoc.width = chreq.width; challoc.height = chreq.height; gtk_widget_size_allocate(ad->applet,&challoc); i += ad->cells; } } else { /*not packed*/ i = panel->size; for(list = g_list_last(panel->applet_list); list!=NULL; list = g_list_previous(list)) { AppletData *ad = list->data; GtkRequisition chreq; gtk_widget_get_child_requisition(ad->applet,&chreq); if(panel->orient == PANEL_HORIZONTAL) ad->cells = chreq.width + pw_applet_padding; else ad->cells = chreq.height + pw_applet_padding; if(ad->pos+ad->cells > i) { ad->pos = i - ad->cells; send_move = g_slist_prepend(send_move,ad); } i = ad->pos; } if(iapplet_list; list!=NULL; list = g_list_next(list)) { AppletData *ad = list->data; if(ad->pos < i) { ad->pos = i; if(!g_slist_find(send_move,ad)) send_move = g_slist_prepend(send_move,ad); } i = ad->pos + ad->cells; } } for(list = panel->applet_list; list!=NULL; list = g_list_next(list)) { AppletData *ad = list->data; GtkAllocation challoc; GtkRequisition chreq; gtk_widget_get_child_requisition(ad->applet,&chreq); if(panel->orient == PANEL_HORIZONTAL) { challoc.x = ad->pos; challoc.y = (allocation->height - chreq.height) / 2; } else { challoc.x = (allocation->width - chreq.width) / 2; challoc.y = ad->pos; } challoc.width = chreq.width; challoc.height = chreq.height; gtk_widget_size_allocate(ad->applet,&challoc); } } if(panel->orient == PANEL_HORIZONTAL) panel->thick = allocation->height; else panel->thick = allocation->width; if(old_thick != panel->thick && panel->fit_pixmap_bg && panel->back_type == PANEL_BACK_PIXMAP) { if(panel->pixmap_resize_timeout) panel->pixmap_resize_pending = TRUE; else { gtk_timeout_add(500,fit_pix_timeout_top,panel); } } for(li=send_move;li!=NULL;li=g_slist_next(li)) { AppletData *ad = li->data; gtk_signal_emit(GTK_OBJECT(panel), panel_widget_signals[APPLET_MOVE_SIGNAL], ad->applet); } g_slist_free(send_move); if (GTK_WIDGET_REALIZED (widget)) { if(!panel->pixmap || allocation->width != panel->pixw || allocation->height != panel->pixh) { if(panel->pixmap) gdk_pixmap_unref(panel->pixmap); panel->pixw = allocation->width; panel->pixh = allocation->height; panel->pixmap = gdk_pixmap_new(widget->window, panel->pixw, panel->pixh, gtk_widget_get_visual(widget)->depth); } panel_widget_draw_all(panel); } } int panel_widget_is_cursor(PanelWidget *panel, int overlap) { int x,y; int w,h; GtkWidget *widget; g_return_val_if_fail(panel!=NULL,FALSE); g_return_val_if_fail(IS_PANEL_WIDGET(panel),FALSE); widget = panel->drop_widget; if(!widget || !GTK_IS_WIDGET(widget) || !GTK_WIDGET_VISIBLE(widget)) return FALSE; gtk_widget_get_pointer(widget, &x, &y); gdk_window_get_size(widget->window, &w, &h); if((x+overlap)>=0 && (x-overlap)<=w && (y+overlap)>=0 && (y-overlap)<=h) return TRUE; return FALSE; } void panel_widget_set_back_pixmap (PanelWidget *panel, char *file) { g_return_if_fail(panel!=NULL); g_return_if_fail(IS_PANEL_WIDGET(panel)); g_return_if_fail(file!=NULL); if (panel_try_to_set_pixmap (panel, file)) { if (panel->back_pixmap) g_free (panel->back_pixmap); panel->back_pixmap = g_strdup (file); panel->back_type = PANEL_BACK_PIXMAP; gtk_signal_emit(GTK_OBJECT(panel), panel_widget_signals[BACK_CHANGE_SIGNAL], panel->back_type, panel->back_pixmap, &panel->back_color); } } static void panel_try_to_set_default_back(PanelWidget *panel) { GtkStyle *ns; g_return_if_fail(panel!=NULL); g_return_if_fail(IS_PANEL_WIDGET(panel)); gtk_widget_set_rc_style(GTK_WIDGET(panel)); panel_widget_draw_all(panel); } static void panel_try_to_set_back_color(PanelWidget *panel, GdkColor *color) { GtkStyle *ns; g_return_if_fail(panel!=NULL); g_return_if_fail(IS_PANEL_WIDGET(panel)); g_return_if_fail(color!=NULL); ns = gtk_style_copy(GTK_WIDGET(panel)->style); gtk_style_ref(ns); ns->bg[GTK_STATE_NORMAL] = panel->back_color = *color; ns->bg[GTK_STATE_NORMAL].pixel = panel->back_color.pixel = 1; /* bogus */ if(ns->bg_pixmap[GTK_STATE_NORMAL]) { gdk_imlib_free_pixmap(ns->bg_pixmap[GTK_STATE_NORMAL]); ns->bg_pixmap[GTK_STATE_NORMAL] = NULL; } gtk_widget_set_style(GTK_WIDGET(panel), ns); gtk_style_unref(ns); panel_widget_draw_all(panel); } void panel_widget_set_back_color(PanelWidget *panel, GdkColor *color) { g_return_if_fail(panel!=NULL); g_return_if_fail(IS_PANEL_WIDGET(panel)); g_return_if_fail(color!=NULL); panel_try_to_set_back_color(panel, color); panel->back_type = PANEL_BACK_COLOR; gtk_signal_emit(GTK_OBJECT(panel), panel_widget_signals[BACK_CHANGE_SIGNAL], panel->back_type, panel->back_pixmap, &panel->back_color); } static void panel_resize_pixmap(PanelWidget *panel) { GdkImlibImage *im; GdkPixmap *p; GtkStyle *ns; int w, h; g_return_if_fail(panel!=NULL); g_return_if_fail(IS_PANEL_WIDGET(panel)); im = gtk_object_get_data(GTK_OBJECT(panel),"gdk_image"); if(!im) return; w = im->rgb_width; h = im->rgb_height; switch (panel->orient) { case PANEL_HORIZONTAL: gdk_imlib_render (im, w * panel->thick / h, panel->thick); break; case PANEL_VERTICAL: gdk_imlib_render (im, panel->thick, h * panel->thick / w); break; default: g_assert_not_reached (); } p = gdk_imlib_move_image (im); ns = gtk_style_copy(GTK_WIDGET(panel)->style); gtk_style_ref(ns); if(ns->bg_pixmap[GTK_STATE_NORMAL]) gdk_imlib_free_pixmap (ns->bg_pixmap[GTK_STATE_NORMAL]); ns->bg_pixmap[GTK_STATE_NORMAL] = p; gtk_widget_set_style(GTK_WIDGET(panel), ns); gtk_style_unref(ns); panel_widget_draw_all(panel); } static int panel_try_to_set_pixmap (PanelWidget *panel, char *pixmap) { GdkImlibImage *im; GdkImlibImage *im2; GdkPixmap *p; GtkStyle *ns; g_return_val_if_fail(panel!=NULL,FALSE); g_return_val_if_fail(IS_PANEL_WIDGET(panel),FALSE); if(!pixmap || strcmp(pixmap,"")==0) { ns = gtk_style_copy(GTK_WIDGET(panel)->style); gtk_style_ref(ns); p = ns->bg_pixmap[GTK_STATE_NORMAL]; if(p) gdk_imlib_free_pixmap (p); ns->bg_pixmap[GTK_STATE_NORMAL] = NULL; gtk_widget_set_style(GTK_WIDGET(panel), ns); gtk_style_unref(ns); panel_widget_draw_all(panel); return TRUE; } if (!g_file_exists (pixmap)) return FALSE; im = gdk_imlib_load_image (pixmap); if (!im) return FALSE; im2 = gtk_object_get_data(GTK_OBJECT(panel),"gdk_image"); if(im2) gdk_imlib_destroy_image (im2); if (panel->fit_pixmap_bg) { int w, h; w = im->rgb_width; h = im->rgb_height; switch (panel->orient) { case PANEL_HORIZONTAL: gdk_imlib_render (im, w * panel->thick / h, panel->thick); break; case PANEL_VERTICAL: gdk_imlib_render (im, panel->thick, h * panel->thick / w); break; default: g_assert_not_reached (); } } else gdk_imlib_render (im, im->rgb_width, im->rgb_height); p = gdk_imlib_move_image (im); ns = gtk_style_copy(GTK_WIDGET(panel)->style); gtk_style_ref(ns); if(ns->bg_pixmap[GTK_STATE_NORMAL]) gdk_imlib_free_pixmap (ns->bg_pixmap[GTK_STATE_NORMAL]); ns->bg_pixmap[GTK_STATE_NORMAL] = p; gtk_widget_set_style(GTK_WIDGET(panel), ns); gtk_style_unref(ns); gtk_object_set_data(GTK_OBJECT(panel),"gdk_image",im); panel_widget_draw_all(panel); return TRUE; } static void panel_widget_realize(GtkWidget *w, gpointer data) { PanelWidget *panel; g_return_if_fail(w!=NULL); g_return_if_fail(IS_PANEL_WIDGET(w)); panel = PANEL_WIDGET(w); if(panel->back_type == PANEL_BACK_PIXMAP) { if (!panel_try_to_set_pixmap (panel, panel->back_pixmap)) panel->back_type = PANEL_BACK_NONE; } else if(panel->back_type == PANEL_BACK_COLOR) { panel_try_to_set_back_color(panel, &panel->back_color); } if(panel->pixmap) gdk_pixmap_unref(panel->pixmap); panel->pixw = w->allocation.width; panel->pixh = w->allocation.height; panel->pixmap = gdk_pixmap_new(w->window, panel->pixw, panel->pixh, gtk_widget_get_visual(w)->depth); panel_widget_draw_all(panel); } static void panel_widget_destroy(GtkWidget *w, gpointer data) { GdkImlibImage *im; g_return_if_fail(w!=NULL); g_return_if_fail(IS_PANEL_WIDGET(w)); im = gtk_object_get_data(GTK_OBJECT(w),"gdk_image"); if(im) gdk_imlib_destroy_image (im); gtk_object_set_data(GTK_OBJECT(w),"gdk_image",NULL); /*remove from panels list*/ panels = g_slist_remove(panels,w); } static int panel_widget_applet_event(GtkWidget *widget, GdkEvent *event, gpointer data); static int is_in_widget(GdkEventButton *bevent, GtkWidget *widget) { g_return_val_if_fail(widget!=NULL,FALSE); g_return_val_if_fail(GTK_IS_WIDGET(widget),FALSE); g_return_val_if_fail(bevent!=NULL,FALSE); if(bevent->x >= widget->allocation.x && bevent->x < (widget->allocation.x + widget->allocation.width) && bevent->y >= widget->allocation.y && bevent->y < (widget->allocation.y + widget->allocation.height)) return TRUE; return FALSE; } static int panel_widget_event(GtkWidget *widget, GdkEvent *event, gpointer data) { PanelWidget *panel; GList *list; GdkEventButton *bevent; g_return_val_if_fail(widget!=NULL,FALSE); g_return_val_if_fail(IS_PANEL_WIDGET(widget),FALSE); g_return_val_if_fail(event!=NULL,FALSE); panel = PANEL_WIDGET(widget); bevent = (GdkEventButton *) event; if((event->type != GDK_BUTTON_PRESS && event->type != GDK_BUTTON_RELEASE) || bevent->window != widget->window) return FALSE; for(list = panel->no_window_applet_list; list!=NULL; list = g_list_next(list)) { AppletData *ad = list->data; if(is_in_widget(bevent,ad->applet) && bevent->button != 1) return panel_widget_applet_event(ad->applet, event,data); } return FALSE; } static void panel_widget_init (PanelWidget *panel) { g_return_if_fail(panel!=NULL); g_return_if_fail(IS_PANEL_WIDGET(panel)); /*this makes the popup "pop down" once the button is released*/ gtk_widget_set_events(GTK_WIDGET(panel), gtk_widget_get_events(GTK_WIDGET(panel)) | GDK_BUTTON_RELEASE_MASK); panel->pixmap = NULL; panel->pixw = panel->pixh = -1; panel->back_type =PANEL_BACK_NONE; panel->fit_pixmap_bg = FALSE; panel->pixmap_resize_timeout = 0; panel->pixmap_resize_pending = FALSE; panel->back_pixmap = NULL; panel->back_color.red = 0; panel->back_color.green = 0; panel->back_color.blue = 0; panel->back_color.pixel = 1; panel->packed = FALSE; panel->orient = PANEL_HORIZONTAL; panel->thick = PANEL_MINIMUM_WIDTH; panel->size = INT_MAX; panel->applet_list = NULL; panel->no_window_applet_list = NULL; panel->master_widget = NULL; panel->drop_widget = GTK_WIDGET(panel); gtk_signal_connect(GTK_OBJECT(panel), "destroy", GTK_SIGNAL_FUNC(panel_widget_destroy), NULL); gtk_signal_connect(GTK_OBJECT(panel), "event", GTK_SIGNAL_FUNC(panel_widget_event), NULL); panels = g_slist_append(panels,panel); } GtkWidget * panel_widget_new (int packed, PanelOrientation orient, PanelBackType back_type, char *back_pixmap, int fit_pixmap_bg, GdkColor *back_color) { PanelWidget *panel; gtk_widget_push_visual (gdk_imlib_get_visual ()); gtk_widget_push_colormap (gdk_imlib_get_colormap ()); panel = gtk_type_new(panel_widget_get_type()); gtk_widget_pop_colormap (); gtk_widget_pop_visual (); panel->back_type = back_type; panel->fit_pixmap_bg = fit_pixmap_bg; if(back_pixmap) panel->back_pixmap = g_strdup(back_pixmap); else panel->back_pixmap = NULL; if(back_color) panel->back_color = *back_color; else { panel->back_color.red = 0; panel->back_color.green = 0; panel->back_color.blue = 0; panel->back_color.pixel = 1; } panel->orient = orient; panel->packed = packed; if(packed) panel->size = 0; else panel->size = INT_MAX; gtk_signal_connect_after(GTK_OBJECT(panel), "realize", GTK_SIGNAL_FUNC(panel_widget_realize), panel); return GTK_WIDGET(panel); } static void _panel_widget_applet_drag_start_no_grab(PanelWidget *panel, GtkWidget *applet) { #ifdef DEBUG g_message("Starting drag on a %s at %p\n", gtk_type_name(GTK_OBJECT(applet)->klass->type), applet); #endif panel->currently_dragged_applet = gtk_object_get_data(GTK_OBJECT(applet), PANEL_APPLET_DATA); } void panel_widget_applet_drag_start_no_grab(PanelWidget *panel, GtkWidget *applet) { g_return_if_fail(panel!=NULL); g_return_if_fail(IS_PANEL_WIDGET(panel)); g_return_if_fail(applet!=NULL); g_return_if_fail(GTK_IS_WIDGET(panel)); panel_applet_in_drag = TRUE; _panel_widget_applet_drag_start_no_grab(panel,applet); } static void _panel_widget_applet_drag_end_no_grab(PanelWidget *panel) { #ifdef DEBUG g_message("Ending drag\n"); #endif panel->currently_dragged_applet = NULL; } void panel_widget_applet_drag_end_no_grab(PanelWidget *panel) { g_return_if_fail(panel!=NULL); g_return_if_fail(IS_PANEL_WIDGET(panel)); _panel_widget_applet_drag_end_no_grab(panel); panel_applet_in_drag = FALSE; } static void _panel_widget_applet_drag_start(PanelWidget *panel, GtkWidget *applet) { #ifdef DEBUG g_message("Starting drag [grabbed] on a %s at %p\n", gtk_type_name(GTK_OBJECT(applet)->klass->type), applet); #endif _panel_widget_applet_drag_start_no_grab(panel,applet); gtk_grab_add(applet); if(applet->window) { GdkCursor *fleur_cursor = gdk_cursor_new(GDK_FLEUR); gdk_pointer_grab(applet->window, FALSE, APPLET_EVENT_MASK, NULL, fleur_cursor, GDK_CURRENT_TIME); gdk_cursor_destroy(fleur_cursor); } } void panel_widget_applet_drag_start(PanelWidget *panel, GtkWidget *applet) { g_return_if_fail(panel!=NULL); g_return_if_fail(IS_PANEL_WIDGET(panel)); g_return_if_fail(applet!=NULL); g_return_if_fail(GTK_IS_WIDGET(panel)); panel_applet_in_drag = TRUE; _panel_widget_applet_drag_start(panel, applet); } static void _panel_widget_applet_drag_end(PanelWidget *panel) { gdk_pointer_ungrab(GDK_CURRENT_TIME); gtk_grab_remove(panel->currently_dragged_applet->applet); _panel_widget_applet_drag_end_no_grab(panel); panel->currently_dragged_applet = NULL; } void panel_widget_applet_drag_end(PanelWidget *panel) { g_return_if_fail(panel!=NULL); g_return_if_fail(IS_PANEL_WIDGET(panel)); _panel_widget_applet_drag_end(panel); panel_applet_in_drag = FALSE; } /*get pos of the cursor location*/ int panel_widget_get_cursorloc(PanelWidget *panel) { int x,y; g_return_val_if_fail(panel!=NULL,-1); g_return_val_if_fail(IS_PANEL_WIDGET(panel),-1); gtk_widget_get_pointer(GTK_WIDGET(panel), &x, &y); if(panel->orient == PANEL_HORIZONTAL) return x; else return y; } /*calculates the value to move the applet by*/ static int panel_widget_get_moveby(PanelWidget *panel, int pos) { int x,y; g_return_val_if_fail(panel!=NULL,-1); g_return_val_if_fail(IS_PANEL_WIDGET(panel),-1); gtk_widget_get_pointer(GTK_WIDGET(panel), &x, &y); if(panel->orient == PANEL_HORIZONTAL) return x - pos; else return y - pos; } static GList * walk_up_to(int pos, GList *list) { AppletData *ad = list->data; g_return_val_if_fail(list!=NULL,NULL); if(ad->pos <= pos && ad->pos+ad->cells > pos) return list; while(g_list_next(list) && ad->pos+ad->cells <= pos) { list = g_list_next(list); ad = list->data; } while(g_list_previous(list) && ad->pos > pos) { list = g_list_previous(list); ad = list->data; } return list; } static GtkWidget * is_in_applet(int pos, AppletData *ad) { g_return_val_if_fail(ad!=NULL,NULL); if(ad->pos <= pos && ad->pos+ad->cells > pos) return ad->applet; return NULL; } static int panel_widget_get_free_spot(PanelWidget *panel, AppletData *ad) { int i,e; int x,y; int place; int start; int right=-1,left=-1; GList *list; g_return_val_if_fail(panel!=NULL,-1); g_return_val_if_fail(IS_PANEL_WIDGET(panel),-1); g_return_val_if_fail(ad!=NULL,-1); gtk_widget_get_pointer(GTK_WIDGET(panel), &x, &y); if(panel->orient == PANEL_HORIZONTAL) place = x; else place = y; if(ad->pos>=panel->size) return -1; if(!panel->applet_list) { if(place+ad->cells>panel->size) return panel->size-ad->cells; else return place; } list = panel->applet_list; start = place-(ad->cells/2); if(startsize;i++) { GtkWidget *applet; list = walk_up_to(i,list); applet = is_in_applet(i,list->data); if(!applet || applet == ad->applet) { e++; if(e>=ad->cells) { right = i-e+1; break; } } else e=0; } start = place+(ad->cells/2); if(start>=panel->size) start = panel->size-1; for(e=0,i=start;i>=0;i--) { GtkWidget *applet; list = walk_up_to(i,list); applet = is_in_applet(i,list->data); if(!applet || applet == ad->applet) { e++; if(e>=ad->cells) { left = i; break; } } else e=0; } start = place-(ad->cells/2); if(left==-1) { if(right==-1) return -1; else return right; } else { if(right==-1) return left; else return abs(left-start)>abs(right-start)?right:left; } } /*to call this function we MUST know that there is at least ad->cells free at pos otherwise we will mess up the panel*/ static void panel_widget_nice_move(PanelWidget *panel, AppletData *ad, int pos) { g_return_if_fail(panel!=NULL); g_return_if_fail(IS_PANEL_WIDGET(panel)); g_return_if_fail(ad!=NULL); if(pos==ad->pos) return; ad->pos = pos; panel->applet_list = my_g_list_resort_item(panel->applet_list,ad, (GCompareFunc)applet_data_compare); gtk_signal_emit(GTK_OBJECT(panel), panel_widget_signals[APPLET_MOVE_SIGNAL], ad->applet); gtk_widget_queue_resize(GTK_WIDGET(panel)); } static int moving_timeout = -1; static int been_moved = FALSE; /*find the cursor position and move the applet to that position*/ int panel_widget_applet_move_to_cursor(PanelWidget *panel) { g_return_val_if_fail(panel!=NULL,FALSE); g_return_val_if_fail(IS_PANEL_WIDGET(panel),FALSE); if (panel->currently_dragged_applet) { int moveby; int pos = panel->currently_dragged_applet->pos; GtkWidget *applet; GSList *forb; applet = panel->currently_dragged_applet->applet; g_assert(GTK_IS_WIDGET(applet)); forb = gtk_object_get_data(GTK_OBJECT(applet), PANEL_APPLET_FORBIDDEN_PANELS); if(!panel_widget_is_cursor(panel,10)) { GSList *list; for(list=panels; list!=NULL; list=g_slist_next(list)) { PanelWidget *new_panel = PANEL_WIDGET(list->data); if(panel != new_panel && panel_widget_is_cursor(new_panel,10) && (!g_slist_find(forb,new_panel))) { pos = panel_widget_get_moveby( new_panel,0); if(pos<0) pos = 0; /*disable reentrancy into this function*/ if(panel_widget_reparent(panel, new_panel, applet, pos)==-1) /*can't find a free pos so cancel the reparent*/ continue; _panel_widget_applet_drag_end(panel); _panel_widget_applet_drag_start( new_panel, applet); return FALSE; } } } if(pw_movement_type == PANEL_SWITCH_MOVE || panel->packed) { moveby = panel_widget_get_moveby(panel,pos); if(moveby != 0) panel_widget_switch_move(panel, panel->currently_dragged_applet, moveby); } else { pos = panel_widget_get_free_spot(panel, panel->currently_dragged_applet); if(pos>=0) panel_widget_nice_move(panel, panel->currently_dragged_applet, pos); } return TRUE; } return FALSE; } static int move_timeout_handler(gpointer data) { PanelWidget *panel = data; g_return_val_if_fail(data!=NULL,FALSE); g_return_val_if_fail(IS_PANEL_WIDGET(data),FALSE); if(been_moved && panel->currently_dragged_applet) { panel_widget_applet_move_to_cursor(panel); been_moved = FALSE; return TRUE; } been_moved = FALSE; moving_timeout = -1; return FALSE; } static int panel_widget_applet_event(GtkWidget *widget, GdkEvent *event, gpointer data) { PanelWidget *panel; GdkEventButton *bevent; g_return_val_if_fail(widget!=NULL,FALSE); g_return_val_if_fail(GTK_IS_WIDGET(widget),FALSE); g_return_val_if_fail(widget->parent!=NULL,FALSE); g_return_val_if_fail(IS_PANEL_WIDGET(widget->parent),FALSE); g_return_val_if_fail(event!=NULL,FALSE); panel = PANEL_WIDGET(widget->parent); g_return_val_if_fail(panel!=NULL,TRUE); switch (event->type) { case GDK_BUTTON_PRESS: bevent = (GdkEventButton *) event; printf("the appwidget %lX\n",(long)widget); /* don't propagate this event */ if (panel->currently_dragged_applet) return TRUE; if(bevent->button == 2) { /* Start drag */ panel_widget_applet_drag_start(panel, widget); return TRUE; } break; case GDK_BUTTON_RELEASE: if (panel->currently_dragged_applet) { panel_widget_applet_drag_end(panel); return TRUE; } break; case GDK_MOTION_NOTIFY: if (panel->currently_dragged_applet) { if(moving_timeout==-1) { been_moved = FALSE; panel_widget_applet_move_to_cursor(panel); moving_timeout = gtk_timeout_add (30,move_timeout_handler,panel); } else been_moved = TRUE; } break; default: break; } return FALSE; } static int panel_sub_event_handler(GtkWidget *widget, GdkEvent *event, gpointer data) { g_return_val_if_fail(widget!=NULL,FALSE); g_return_val_if_fail(GTK_IS_WIDGET(widget),FALSE); g_return_val_if_fail(event!=NULL,FALSE); switch (event->type) { GdkEventButton *bevent; /*pass these to the parent!*/ case GDK_BUTTON_PRESS: case GDK_BUTTON_RELEASE: case GDK_MOTION_NOTIFY: bevent = (GdkEventButton *)event; if(bevent->button != 1 || panel_applet_in_drag) return gtk_widget_event(data, event); break; default: break; } return FALSE; } static void bind_applet_events(GtkWidget *widget, gpointer data) { g_return_if_fail(widget!=NULL); g_return_if_fail(GTK_IS_WIDGET(widget)); /* XXX: This is more or less a hack. We need to be able to * capture events over applets so that we can drag them with * the mouse and such. So we need to force the applet's * widgets to recursively send the events back to their parent * until the event gets to the applet wrapper (the * GtkEventBox) for processing by us. */ if (!GTK_WIDGET_NO_WINDOW(widget)) gtk_signal_connect(GTK_OBJECT(widget), "event", (GtkSignalFunc) panel_sub_event_handler, data); if (GTK_IS_CONTAINER(widget)) gtk_container_foreach (GTK_CONTAINER (widget), bind_applet_events, data); } static void panel_widget_applet_destroy(GtkWidget *applet, gpointer data) { AppletData *ad; g_return_if_fail(applet!=NULL); g_return_if_fail(GTK_IS_WIDGET(applet)); ad = gtk_object_get_data(GTK_OBJECT(applet), PANEL_APPLET_DATA); /*if it wasn't yet removed*/ if(applet->parent) { PanelWidget *panel = PANEL_WIDGET(applet->parent); if(panel->currently_dragged_applet == ad) panel->currently_dragged_applet = NULL; panel->applet_list = g_list_remove(panel->applet_list,ad); panel->no_window_applet_list = g_list_remove (panel->no_window_applet_list, ad); } g_free(ad); } static void bind_top_applet_events(GtkWidget *widget, int bind_lower) { g_return_if_fail(widget!=NULL); g_return_if_fail(GTK_IS_WIDGET(widget)); gtk_signal_connect(GTK_OBJECT(widget), "destroy", GTK_SIGNAL_FUNC(panel_widget_applet_destroy), NULL); gtk_signal_connect(GTK_OBJECT(widget), "event", GTK_SIGNAL_FUNC(panel_widget_applet_event), NULL); /* XXX: This is more or less a hack. We need to be able to * capture events over applets so that we can drag them with * the mouse and such. So we need to force the applet's * widgets to recursively send the events back to their parent * until the event gets to the applet wrapper (the * GtkEventBox) for processing by us. */ if (bind_lower && GTK_IS_CONTAINER(widget)) gtk_container_foreach (GTK_CONTAINER (widget), bind_applet_events, widget); } static int panel_widget_find_empty_pos(PanelWidget *panel, int pos) { int i; int right=-1,left=-1; GList *list; g_return_val_if_fail(panel!=NULL,-1); g_return_val_if_fail(IS_PANEL_WIDGET(panel),-1); g_return_val_if_fail(pos>=0,-1); if(pos>=panel->size) pos = panel->size-1; if(!panel->applet_list) return pos; list = panel->applet_list; for(i=pos;isize;i++) { list = walk_up_to(i,list); if(!is_in_applet(i,list->data)) { right = i; break; } } for(i=pos;i>=pw_applet_padding;i--) { list = walk_up_to(i,list); if(!is_in_applet(i,list->data)) { left = i; break; } } if(left==-1) { if(right==-1) return -1; else return right; } else { if(right==-1) return left; else return abs(left-pos)>abs(right-pos)?right:left; } } void panel_widget_add_forbidden(PanelWidget *panel) { g_return_if_fail(panel!=NULL); g_return_if_fail(IS_PANEL_WIDGET(panel)); add_panel_to_forbidden(panel,panel); } int panel_widget_add_full (PanelWidget *panel, GtkWidget *applet, int pos, int bind_lower_events) { AppletData *ad = NULL; g_return_val_if_fail(panel!=NULL,-1); g_return_val_if_fail(IS_PANEL_WIDGET(panel),-1); g_return_val_if_fail(applet!=NULL,-1); g_return_val_if_fail(GTK_IS_WIDGET(applet),-1); g_return_val_if_fail(pos>=0,-1); ad = gtk_object_get_data(GTK_OBJECT(applet),PANEL_APPLET_DATA); if(ad) pos = ad->pos; if(pospacked) { if(get_applet_list_pos(panel,pos)) /*this is a slight hack so that this applet is inserted AFTER an applet with this pos number*/ pos++; } else pos = panel_widget_find_empty_pos(panel,pos); if(pos==-1) return -1; if(!ad) { ad = g_new(AppletData,1); ad->applet = applet; ad->cells = 1; ad->pos = pos; gtk_object_set_data(GTK_OBJECT(applet),PANEL_APPLET_DATA,ad); /*this is a completely new applet, which was not yet bound*/ bind_top_applet_events(applet,bind_lower_events); } panel->applet_list = g_list_insert_sorted(panel->applet_list,ad, (GCompareFunc)applet_data_compare); if(GTK_WIDGET_NO_WINDOW(applet)) panel->no_window_applet_list = g_list_prepend(panel->no_window_applet_list,ad); /*this will get done right on size allocate!*/ if(panel->orient == PANEL_HORIZONTAL) gtk_fixed_put(GTK_FIXED(panel),applet, pos,0); else gtk_fixed_put(GTK_FIXED(panel),applet, 0,pos); gtk_widget_queue_resize(GTK_WIDGET(panel)); gtk_signal_emit(GTK_OBJECT(panel), panel_widget_signals[APPLET_ADDED_SIGNAL], applet); /*NOTE: forbidden list is not updated on addition, use the function above for the panel*/ return pos; } int panel_widget_reparent (PanelWidget *old_panel, PanelWidget *new_panel, GtkWidget *applet, int pos) { AppletData *ad; g_return_val_if_fail(old_panel!=NULL,-1); g_return_val_if_fail(IS_PANEL_WIDGET(old_panel),-1); g_return_val_if_fail(new_panel!=NULL,-1); g_return_val_if_fail(IS_PANEL_WIDGET(new_panel),-1); g_return_val_if_fail(applet!=NULL,-1); g_return_val_if_fail(GTK_IS_WIDGET(applet),-1); g_return_val_if_fail(pos>=0,-1); ad = gtk_object_get_data(GTK_OBJECT(applet), PANEL_APPLET_DATA); g_return_val_if_fail(ad!=NULL,-1); ad->pos = pos; /*reparent applet*/ if (IS_BUTTON_WIDGET (applet)) { gtk_widget_ref (applet); gtk_container_remove (GTK_CONTAINER (applet->parent), applet); gtk_container_add (GTK_CONTAINER (new_panel), applet); gtk_widget_unref (applet); } else gtk_widget_reparent(applet,GTK_WIDGET(new_panel)); return pos; } int panel_widget_move (PanelWidget *panel, GtkWidget *applet, int pos) { AppletData *ad; g_return_val_if_fail(panel!=NULL,-1); g_return_val_if_fail(IS_PANEL_WIDGET(panel),-1); g_return_val_if_fail(applet!=NULL,-1); g_return_val_if_fail(GTK_IS_WIDGET(applet),-1); g_return_val_if_fail(pos>=0,-1); ad = gtk_object_get_data(GTK_OBJECT(applet), PANEL_APPLET_DATA); ad->pos = -1; panel->applet_list = g_list_remove(panel->applet_list,ad); panel->no_window_applet_list = g_list_remove(panel->no_window_applet_list,ad); if(pospos = pos; /*reset size to 1*/ ad->cells = 1; panel->applet_list = g_list_insert_sorted(panel->applet_list,ad, (GCompareFunc)applet_data_compare); if(GTK_WIDGET_NO_WINDOW(ad->applet)) panel->no_window_applet_list = g_list_remove(panel->no_window_applet_list,ad); gtk_signal_emit(GTK_OBJECT(panel), panel_widget_signals[APPLET_MOVE_SIGNAL], ad->applet); gtk_widget_queue_resize(GTK_WIDGET(panel)); return pos; } int panel_widget_get_pos(PanelWidget *panel, GtkWidget *applet) { AppletData *ad; g_return_val_if_fail(panel!=NULL,-1); g_return_val_if_fail(IS_PANEL_WIDGET(panel),-1); g_return_val_if_fail(applet!=NULL,-1); g_return_val_if_fail(GTK_IS_WIDGET(applet),-1); ad = gtk_object_get_data(GTK_OBJECT(applet), PANEL_APPLET_DATA); g_return_val_if_fail(ad,-1); if(panel != PANEL_WIDGET(applet->parent)) return -1; return ad->pos; } void panel_widget_change_params(PanelWidget *panel, PanelOrientation orient, PanelBackType back_type, char *pixmap, int fit_pixmap_bg, GdkColor *back_color) { PanelOrientation oldorient; int change_back = FALSE; g_return_if_fail(panel!=NULL); g_return_if_fail(IS_PANEL_WIDGET(panel)); g_return_if_fail(GTK_WIDGET_REALIZED(panel)); oldorient = panel->orient; panel->orient = orient; if(oldorient != panel->orient) { gtk_signal_emit(GTK_OBJECT(panel), panel_widget_signals[ORIENT_CHANGE_SIGNAL], panel->orient); } if(back_color) { /*this will allways trigger, but so what*/ if(back_type == PANEL_BACK_COLOR) change_back = TRUE; panel->back_color = *back_color; } /*if we didn't pass a color, then don't set a new color!*/ /*only change the pixmap name if we passed a non-null value*/ if(pixmap && pixmap != panel->back_pixmap) { if(back_type == PANEL_BACK_PIXMAP) change_back = TRUE; if (panel->back_pixmap) g_free (panel->back_pixmap); panel->back_pixmap = g_strdup (pixmap); } /*clearly a signal should be sent*/ if(panel->back_type != back_type) change_back = TRUE; /*this bit is not optimal, it allways sets the pixmap etc etc ... but this function isn't called too often*/ panel->back_type = back_type; panel->fit_pixmap_bg = fit_pixmap_bg; if(back_type == PANEL_BACK_PIXMAP) { panel_try_to_set_pixmap (panel, panel->back_pixmap); } else if(back_type == PANEL_BACK_COLOR) { panel_try_to_set_back_color(panel, &panel->back_color); } else { panel_try_to_set_default_back(panel); } /* let the applets know we changed the background */ if(change_back) { gtk_signal_emit(GTK_OBJECT(panel), panel_widget_signals[BACK_CHANGE_SIGNAL], panel->back_type, panel->back_pixmap, &panel->back_color); } gtk_widget_queue_resize(GTK_WIDGET(panel)); } void panel_widget_change_orient(PanelWidget *panel, PanelOrientation orient) { panel_widget_change_params(panel, orient, panel->back_type, panel->back_pixmap, panel->fit_pixmap_bg, &panel->back_color); } /*change global params*/ void panel_widget_change_global(int explicit_step, int auto_step, int drawer_step, int minimized_size, int minimize_delay, PanelMovementType move_type, int disable_animations, int applet_padding) { if(explicit_step>0) pw_explicit_step=explicit_step; if(auto_step>0) pw_auto_step=auto_step; if(drawer_step>0) pw_drawer_step=drawer_step; if(minimized_size>0) pw_minimized_size=minimized_size; if(minimize_delay>=0) pw_minimize_delay=minimize_delay; pw_movement_type = move_type; pw_disable_animations = disable_animations; /*change padding on all panels NOW*/ if(pw_applet_padding != applet_padding) { GSList *li; pw_applet_padding = applet_padding; for(li=panels;li!=NULL;li=g_slist_next(li)) gtk_widget_queue_resize(li->data); } }