From c55d8d0e3c5eb570e15c130360411c07fdce9e5f Mon Sep 17 00:00:00 2001 From: EricDWertz Date: Mon, 19 Sep 2016 10:12:21 -0400 Subject: [PATCH] Breaking out icons/pager items/tooltip window... fixed winkey+number shortcuts and tooltip window rendering --- dock_icon.h | 126 +++++++++++++++++++++++++++++++++++++++ drawing.h | 20 +++++++ pager_item.h | 96 ++++++++++++++++++++++++++++++ tooltip_window.h | 151 +++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 393 insertions(+) create mode 100644 dock_icon.h create mode 100644 drawing.h create mode 100644 pager_item.h create mode 100644 tooltip_window.h diff --git a/dock_icon.h b/dock_icon.h new file mode 100644 index 0000000..b1bf3ed --- /dev/null +++ b/dock_icon.h @@ -0,0 +1,126 @@ +#pragma once +/* + * dock_icon - Represents an icon on the dock + * holds pager_items + * + * renders/handles events based on how many pager_items it contains + */ +#include + +#define WNCK_I_KNOW_THIS_IS_UNSTABLE +#include + +typedef struct +{ + WnckClassGroup* class_group; + GdkPixbuf* icon_pixbuf; + GList* pager_items; + double x, y; + double width, height; + int icon_state; + int is_active; + int selected_index; +} dock_icon; + +#include "tooltip_window.h" + +extern dock_icon* tooltip_window_icon; + +dock_icon* dock_icon_create( WnckClassGroup* class_group ) +{ + dock_icon* icon = malloc( sizeof( dock_icon ) ); + icon->class_group = class_group; + icon->icon_pixbuf = wnck_class_group_get_icon( class_group ); + icon->pager_items = NULL; + icon->icon_state = ICON_STATE_NORMAL; + + icon->width = SCALE_VALUE( 42 ); + icon->height = SCALE_VALUE( 48 ); + + icon->selected_index = 0; + + return icon; +} + +//Goes to the next pager item, looping back to the start if necessary +pager_item* dock_icon_get_next_pager_item( dock_icon* icon ) +{ + pager_item* item; + + icon->selected_index++; + if( icon->selected_index >= g_list_length( icon->pager_items ) ) + { + icon->selected_index = 0; + } + + item = g_list_nth_data( icon->pager_items, icon->selected_index ); + + return item; +} + +void dock_icon_clear_pager_item_state( dock_icon* icon ) +{ + GList* pager_list; + pager_item* item; + + for( pager_list = icon->pager_items; pager_list != NULL; pager_list = pager_list->next ) + { + item = pager_list->data; + item->icon_state = ICON_STATE_NORMAL; + } +} + +/* Event whenever a dock icon is clicked or selected via keyboard + * Will switch to app, or if more than one pager_items, show menu + */ +void dock_icon_activate( dock_icon* icon, Time time, int from_click ) +{ + if( !icon->pager_items ) + return; + + if( g_list_length( icon->pager_items ) > 1 ) + { + pager_item* item; + + dock_icon_clear_pager_item_state( icon ); + + if( tooltip_window_icon != icon ) + { + tooltip_window_icon = icon; + tooltip_window_show(); + icon->selected_index = 0; + item = (pager_item*)icon->pager_items->data; + } + else + { + item = dock_icon_get_next_pager_item( icon ); + } + + if( !from_click ) + { + item->icon_state = ICON_STATE_HOVER; + wnck_window_activate( item->window, time ); + gtk_widget_queue_draw( tooltip_window->window ); + } + } + else + { + //Activiate the only one we have + pager_item* item = (pager_item*)icon->pager_items->data; + wnck_window_activate( item->window, time ); + tooltip_window_hide(); + } +} + +void dock_icon_mouse_down( dock_icon* icon, double mx, double my, Time time ) +{ + double it, ib, il, ir; + + il = icon->x; ir = icon->x + icon->width; + it = icon->y; ib = icon->y + icon->height; + + if( il < mx && mx < ir && it < my && my < ib ) + { + dock_icon_activate( icon, time, TRUE ); + } +} diff --git a/drawing.h b/drawing.h new file mode 100644 index 0000000..9d9394c --- /dev/null +++ b/drawing.h @@ -0,0 +1,20 @@ +#pragma once +/* + * Drawing functions! + */ +#include + +void draw_rounded_rect(cairo_t* cr,double x,double y,double w,double h,double r) +{ + cairo_move_to(cr,x+r,y); + cairo_line_to(cr,x+w-r*2,y); + cairo_arc(cr,x+w-r,y+r,r,-M_PI/2.0,0); + cairo_line_to(cr,x+w,y+h-r*2); + cairo_arc(cr,x+w-r,y+h-r,r,0,M_PI/2.0); + cairo_line_to(cr, x+r,y+h); + cairo_arc(cr,x+r,y+h-r,r,M_PI/2.0,M_PI); + cairo_line_to(cr, x, y+r); + cairo_arc(cr,x+r,y+r,r,M_PI,-M_PI/2.0); + cairo_close_path(cr); +} + diff --git a/pager_item.h b/pager_item.h new file mode 100644 index 0000000..7121ba4 --- /dev/null +++ b/pager_item.h @@ -0,0 +1,96 @@ +#pragma once +/* + * pager_item - held by the dock_icon object + */ + +#include + +#define WNCK_I_KNOW_THIS_IS_UNSTABLE +#include + +#include "drawing.h" + +//Structure to hold actual pager items +typedef struct +{ + WnckWindow* window; + char name[256]; + GdkPixbuf* icon_pixbuf; + double x, y; + double width, height; + double text_height; + int icon_state; +} pager_item; + +void pager_item_name_changed( WnckWindow* window, pager_item* item ) +{ + strcpy( item->name, wnck_window_get_name( window ) ); +} + +void pager_item_icon_changed( WnckWindow* window, pager_item* item ) +{ + item->icon_pixbuf = wnck_window_get_mini_icon( window ); +} + +pager_item* pager_item_create( WnckWindow* window ) +{ + pager_item* item = malloc( sizeof( pager_item ) ); + item->window = window; + strcpy( item->name, wnck_window_get_name( item->window ) ); + item->icon_pixbuf = wnck_window_get_mini_icon( item->window ); + item->icon_state = ICON_STATE_NORMAL; + + g_signal_connect( G_OBJECT( window ), "name-changed", G_CALLBACK( pager_item_name_changed ), (gpointer)item ); + g_signal_connect( G_OBJECT( window ), "icon-changed", G_CALLBACK( pager_item_name_changed ), (gpointer)item ); + + item->width = SCALE_VALUE( 320 ); + item->height = SCALE_VALUE( 24.0 ); + item->text_height = SCALE_VALUE( 16.0 ); + + return item; +} + +/* Returns bool if state has changed */ +int pager_item_mouse_move( pager_item* item, double mx, double my ) +{ + double it, ib, il, ir; + int old_state, state_changed; + + old_state = item->icon_state; + + il = item->x; ir = item->x + item->width; + it = item->y; ib = item->y + item->height; + + if( il < mx && mx < ir && it < my && my < ib ) + { + item->icon_state = ICON_STATE_HOVER; + } + else + { + item->icon_state = ICON_STATE_NORMAL; + } + + return old_state != item->icon_state; +} + +void pager_item_draw( pager_item* item, cairo_t* cr, eric_window* w, cairo_pattern_t* pattern ) +{ + if( item->icon_state == ICON_STATE_HOVER ) + { + w->text_color.alpha = 0.25; + gdk_cairo_set_source_rgba( cr, &w->text_color ); + draw_rounded_rect( cr, item->x, item->y, + item->width, item->height, SCALE_VALUE( 2.0 ) ); + cairo_fill( cr ); + } + + gdk_cairo_set_source_pixbuf( cr, item->icon_pixbuf, item->x, item->y + SCALE_VALUE( 6.0 ) ); + cairo_paint( cr ); + + cairo_set_source( cr, pattern ); + cairo_move_to( cr, item->x + SCALE_VALUE( 20.0 ), item->y + item->text_height ); + cairo_text_path( cr, item->name ); + + cairo_fill( cr ); + +} diff --git a/tooltip_window.h b/tooltip_window.h new file mode 100644 index 0000000..ca0c618 --- /dev/null +++ b/tooltip_window.h @@ -0,0 +1,151 @@ +#pragma once + +#define WNCK_I_KNOW_THIS_IS_UNSTABLE +#include + +#include "eric_window.h" +#include "dock_icon.h" +#include "drawing.h" + +eric_window* tooltip_window = NULL; +dock_icon* tooltip_window_icon = NULL; + +void tooltip_window_hide() +{ + tooltip_window_icon = NULL; + gtk_widget_hide( tooltip_window->window ); +} + +gboolean tooltip_window_lose_focus( GtkWidget* widget, GdkEvent* event, gpointer user ) +{ + tooltip_window_hide(); + return TRUE; +} + +void tooltip_window_mouse_down( GtkWidget* widget, GdkEvent* event, gpointer user ) +{ + GdkEventButton* e = (GdkEventButton*)event; + if( e->button != 1 ) + return; + + double mx, my; + double it, ib, il, ir; + dock_icon* icon; + pager_item* item; + GList* pager_list; + + mx = e->x; my = e->y; + for( pager_list = tooltip_window_icon->pager_items; pager_list != NULL; pager_list = pager_list->next ) + { + item = pager_list->data; + if( my > item->y && my < item->y + SCALE_VALUE( 24.0 ) ) + { + wnck_window_activate( item->window, e->time ); + tooltip_window_hide(); + } + } +} + +gboolean tooltip_window_mouse_move( GtkWidget* widget, GdkEvent* event, gpointer user ) +{ + double mx, my; + double it, ib, il, ir; + int old_state, new_state, state_changed; + dock_icon* icon; + pager_item* item; + GList *icon_list, *item_list; + GdkEventMotion* e = (GdkEventMotion*)event; + + mx = e->x; + my = e->y; + + for( item_list = tooltip_window_icon->pager_items; item_list != NULL; item_list = item_list->next ) + { + item = item_list->data; + + + if( pager_item_mouse_move( item, mx, my ) ) + state_changed = TRUE; + } + + if( state_changed ) + gtk_widget_queue_draw( tooltip_window->window ); + + return FALSE; +} + +static gboolean tooltip_window_draw( GtkWidget* widget, cairo_t* cr, eric_window* w ) +{ + double x, y; + GList* pager_list; + pager_item* item; + cairo_pattern_t* pattern; + + cairo_set_operator( cr, CAIRO_OPERATOR_OVER ); + w->text_color.alpha = 1.0; + cairo_set_font_face( cr, cairo_toy_font_face_create( ERIC_DOCK_FONT, CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL ) ); + cairo_set_font_size( cr, SCALE_VALUE( 12.0 ) ); + + x = SCALE_VALUE( 5.0 ); //margin-left + y = SCALE_VALUE( 2.0 ); //margin-top + pattern = cairo_pattern_create_linear( SCALE_VALUE( ERIC_DOCK_TOOLTIP_WIDTH - 21.0 ), 0, SCALE_VALUE( ERIC_DOCK_TOOLTIP_WIDTH - 5.0 ), 0 ); + cairo_pattern_add_color_stop_rgba( pattern, 0.0, w->text_color.red, w->text_color.green, w->text_color.blue, 1.0 ); + cairo_pattern_add_color_stop_rgba( pattern, 1.0, w->text_color.red, w->text_color.green, w->text_color.blue, 0.0 ); + for( pager_list = tooltip_window_icon->pager_items; pager_list != NULL; pager_list = pager_list->next ) + { + item = (pager_item*)pager_list->data; + + item->x = x; + item->y = y; + pager_item_draw( item, cr, w, pattern ); + + y += SCALE_VALUE( 24.0 ); + } + + cairo_pattern_destroy( pattern ); +} + + + +void tooltip_window_create( GtkWidget* dock_window ) +{ + eric_window* w = eric_window_create( 10, 10, "" ); + gtk_window_move( GTK_WINDOW( w->window ), 0, 1040 ); + gtk_window_set_type_hint( GTK_WINDOW( w->window ), GDK_WINDOW_TYPE_HINT_DIALOG ); + gtk_window_set_decorated( GTK_WINDOW( w->window ), FALSE ); + gtk_window_set_skip_pager_hint( GTK_WINDOW( w->window ), TRUE ); + gtk_window_set_transient_for( GTK_WINDOW( w->window ), GTK_WINDOW( dock_window ) ); + gtk_window_set_keep_above( GTK_WINDOW( w->window ), TRUE ); + + gtk_widget_add_events( w->window, GDK_POINTER_MOTION_MASK | GDK_BUTTON_PRESS_MASK ); + g_signal_connect( G_OBJECT( w->window ), "focus-out-event", G_CALLBACK(tooltip_window_lose_focus), NULL ); + g_signal_connect( G_OBJECT( w->window ), "motion-notify-event", G_CALLBACK(tooltip_window_mouse_move), NULL ); + g_signal_connect( G_OBJECT( w->window ), "button-press-event", G_CALLBACK(tooltip_window_mouse_down), NULL ); + w->draw_callback = tooltip_window_draw; + + tooltip_window = w; +} + + +void tooltip_window_update_geometry() +{ + int pager_count; + int wx, wy; + + pager_count = g_list_length( tooltip_window_icon->pager_items ); + + gtk_window_get_position( GTK_WINDOW( dock_window->window ), &wx, &wy ); + gtk_window_resize( GTK_WINDOW( tooltip_window->window ), SCALE_VALUE(ERIC_DOCK_TOOLTIP_WIDTH), SCALE_VALUE( pager_count * 24 ) ); + gtk_window_move( GTK_WINDOW( tooltip_window->window ), wx + (int)tooltip_window_icon->x, wy - (int)SCALE_VALUE( pager_count * 24 ) ); +} + +void tooltip_window_show() +{ + int wx, wy; + int w, h; + + tooltip_window_update_geometry(); + gtk_widget_show_all( tooltip_window->window ); + gtk_widget_queue_draw( tooltip_window->window ); +} + -- 2.47.0