1 2 #ifdef ENABLE_QUICKSTART_APPLET 3 4 #include <unotools/moduleoptions.hxx> 5 #include <unotools/dynamicmenuoptions.hxx> 6 7 #include <gtk/gtk.h> 8 #include <glib.h> 9 #include <vos/mutex.hxx> 10 #include <vcl/bitmapex.hxx> 11 #include <vcl/bmpacc.hxx> 12 #include <sfx2/app.hxx> 13 #ifndef _SFX_APP_HRC 14 #include "app.hrc" 15 #endif 16 #ifndef __SHUTDOWNICON_HXX__ 17 #define USE_APP_SHORTCUTS 18 #include "shutdownicon.hxx" 19 #endif 20 21 // Cut/paste from vcl/inc/svids.hrc 22 #define SV_ICON_LARGE_START 24000 23 #define SV_ICON_SMALL_START 25000 24 25 #define SV_ICON_ID_OFFICE 1 26 #define SV_ICON_ID_TEXT 2 27 #define SV_ICON_ID_SPREADSHEET 4 28 #define SV_ICON_ID_DRAWING 6 29 #define SV_ICON_ID_PRESENTATION 8 30 #define SV_ICON_ID_DATABASE 14 31 #define SV_ICON_ID_FORMULA 15 32 #define SV_ICON_ID_TEMPLATE 16 33 34 using namespace ::rtl; 35 using namespace ::osl; 36 37 static ResMgr *pVCLResMgr; 38 static GtkStatusIcon *pTrayIcon; 39 static GtkWidget *pExitMenuItem = NULL; 40 static GtkWidget *pOpenMenuItem = NULL; 41 static GtkWidget *pDisableMenuItem = NULL; 42 43 static void open_url_cb( GtkWidget *, gpointer data ) 44 { 45 ShutdownIcon::OpenURL( *(OUString *)data, 46 OUString( RTL_CONSTASCII_USTRINGPARAM( "_default" ) ) ); 47 } 48 49 static void open_file_cb( GtkWidget * ) 50 { 51 if ( !ShutdownIcon::bModalMode ) 52 ShutdownIcon::FileOpen(); 53 } 54 55 static void open_template_cb( GtkWidget * ) 56 { 57 if ( !ShutdownIcon::bModalMode ) 58 ShutdownIcon::FromTemplate(); 59 } 60 61 static void systray_disable_cb() 62 { 63 ShutdownIcon::SetAutostart( false ); 64 ShutdownIcon::terminateDesktop(); 65 } 66 67 static void exit_quickstarter_cb( GtkWidget * ) 68 { 69 ShutdownIcon::getInstance()->terminateDesktop(); 70 plugin_shutdown_sys_tray(); 71 } 72 73 static void menu_deactivate_cb( GtkWidget *pMenu ) 74 { 75 gtk_menu_popdown( GTK_MENU( pMenu ) ); 76 } 77 78 static GdkPixbuf * ResIdToPixbuf( sal_uInt16 nResId ) 79 { 80 ResId aResId( nResId, *pVCLResMgr ); 81 BitmapEx aIcon( aResId ); 82 Bitmap pInSalBitmap = aIcon.GetBitmap(); 83 AlphaMask pInSalAlpha = aIcon.GetAlpha(); 84 85 BitmapReadAccess* pSalBitmap = pInSalBitmap.AcquireReadAccess(); 86 BitmapReadAccess* pSalAlpha = pInSalAlpha.AcquireReadAccess(); 87 88 g_return_val_if_fail( pSalBitmap != NULL, NULL ); 89 90 Size aSize( pSalBitmap->Width(), pSalBitmap->Height() ); 91 g_return_val_if_fail( Size( pSalAlpha->Width(), pSalAlpha->Height() ) == aSize, NULL ); 92 93 int nX, nY; 94 guchar *pPixbufData = ( guchar * )g_malloc( 4 * aSize.Width() * aSize.Height() ); 95 guchar *pDestData = pPixbufData; 96 97 for( nY = 0; nY < pSalBitmap->Height(); nY++ ) 98 { 99 for( nX = 0; nX < pSalBitmap->Width(); nX++ ) 100 { 101 BitmapColor aPix; 102 aPix = pSalBitmap->GetPixel( nY, nX ); 103 pDestData[0] = aPix.GetRed(); 104 pDestData[1] = aPix.GetGreen(); 105 pDestData[2] = aPix.GetBlue(); 106 if (pSalAlpha) 107 { 108 aPix = pSalAlpha->GetPixel( nY, nX ); 109 pDestData[3] = 255 - aPix.GetIndex(); 110 } 111 else 112 pDestData[3] = 255; 113 pDestData += 4; 114 } 115 } 116 117 pInSalBitmap.ReleaseAccess( pSalBitmap ); 118 if( pSalAlpha ) 119 pInSalAlpha.ReleaseAccess( pSalAlpha ); 120 121 return gdk_pixbuf_new_from_data( pPixbufData, 122 GDK_COLORSPACE_RGB, sal_True, 8, 123 aSize.Width(), aSize.Height(), 124 aSize.Width() * 4, 125 (GdkPixbufDestroyNotify) g_free, 126 NULL ); 127 } 128 129 extern "C" { 130 static void oustring_delete (gpointer data, 131 GClosure * /* closure */) 132 { 133 OUString *pURL = (OUString *) data; 134 delete pURL; 135 } 136 } 137 138 static void add_item( GtkMenuShell *pMenuShell, const char *pAsciiURL, 139 OUString *pOverrideLabel, 140 sal_uInt16 nResId, GCallback pFnCallback ) 141 { 142 OUString *pURL = new OUString (OStringToOUString( pAsciiURL, 143 RTL_TEXTENCODING_UTF8 )); 144 OString aLabel; 145 if (pOverrideLabel) 146 aLabel = OUStringToOString (*pOverrideLabel, RTL_TEXTENCODING_UTF8); 147 else 148 { 149 ShutdownIcon *pShutdownIcon = ShutdownIcon::getInstance(); 150 aLabel = OUStringToOString (pShutdownIcon->GetUrlDescription( *pURL ), 151 RTL_TEXTENCODING_UTF8); 152 } 153 154 GdkPixbuf *pPixbuf= ResIdToPixbuf( SV_ICON_SMALL_START + nResId ); 155 GtkWidget *pImage = gtk_image_new_from_pixbuf( pPixbuf ); 156 g_object_unref( G_OBJECT( pPixbuf ) ); 157 158 GtkWidget *pMenuItem = gtk_image_menu_item_new_with_label( aLabel ); 159 gtk_image_menu_item_set_image( GTK_IMAGE_MENU_ITEM( pMenuItem ), pImage ); 160 g_signal_connect_data( pMenuItem, "activate", pFnCallback, pURL, 161 oustring_delete, GConnectFlags(0)); 162 163 gtk_menu_shell_append( pMenuShell, pMenuItem ); 164 } 165 166 // Unbelievably nasty 167 using namespace ::com::sun::star::uno; 168 using namespace ::com::sun::star::task; 169 using namespace ::com::sun::star::lang; 170 using namespace ::com::sun::star::beans; 171 172 static void add_ugly_db_item( GtkMenuShell *pMenuShell, const char *pAsciiURL, 173 sal_uInt16 nResId, GCallback pFnCallback ) 174 { 175 SvtDynamicMenuOptions aOpt; 176 Sequence < Sequence < PropertyValue > > aMenu = aOpt.GetMenu( E_NEWMENU ); 177 for ( sal_Int32 n=0; n<aMenu.getLength(); n++ ) 178 { 179 ::rtl::OUString aURL; 180 ::rtl::OUString aDescription; 181 Sequence < PropertyValue >& aEntry = aMenu[n]; 182 for ( sal_Int32 m=0; m<aEntry.getLength(); m++ ) 183 { 184 if ( aEntry[m].Name.equalsAsciiL( "URL", 3 ) ) 185 aEntry[m].Value >>= aURL; 186 if ( aEntry[m].Name.equalsAsciiL( "Title", 5 ) ) 187 aEntry[m].Value >>= aDescription; 188 } 189 190 if ( aURL.equalsAscii( BASE_URL ) && aDescription.getLength() ) 191 { 192 add_item (pMenuShell, pAsciiURL, &aDescription, nResId, pFnCallback); 193 break; 194 } 195 } 196 } 197 198 static GtkWidget * 199 add_image_menu_item( GtkMenuShell *pMenuShell, 200 const gchar *stock_id, 201 rtl::OUString aLabel, 202 GCallback activate_cb ) 203 { 204 OString aUtfLabel = rtl::OUStringToOString (aLabel, RTL_TEXTENCODING_UTF8 ); 205 206 GtkWidget *pImage; 207 pImage = gtk_image_new_from_stock( stock_id, GTK_ICON_SIZE_MENU ); 208 209 GtkWidget *pMenuItem; 210 pMenuItem = gtk_image_menu_item_new_with_label( aUtfLabel ); 211 gtk_image_menu_item_set_image( GTK_IMAGE_MENU_ITEM( pMenuItem ), pImage ); 212 213 gtk_menu_shell_append( pMenuShell, pMenuItem ); 214 g_signal_connect( pMenuItem, "activate", activate_cb, NULL); 215 216 return pMenuItem; 217 } 218 219 static void populate_menu( GtkWidget *pMenu ) 220 { 221 ShutdownIcon *pShutdownIcon = ShutdownIcon::getInstance(); 222 GtkMenuShell *pMenuShell = GTK_MENU_SHELL( pMenu ); 223 SvtModuleOptions aModuleOptions; 224 225 if ( aModuleOptions.IsWriter() ) 226 add_item (pMenuShell, WRITER_URL, NULL, 227 SV_ICON_ID_TEXT, G_CALLBACK( open_url_cb )); 228 229 if ( aModuleOptions.IsCalc() ) 230 add_item (pMenuShell, CALC_URL, NULL, 231 SV_ICON_ID_SPREADSHEET, G_CALLBACK( open_url_cb )); 232 233 if ( aModuleOptions.IsImpress() ) 234 add_item (pMenuShell, IMPRESS_URL, NULL, 235 SV_ICON_ID_PRESENTATION, G_CALLBACK( open_url_cb )); 236 237 if ( aModuleOptions.IsDraw() ) 238 add_item (pMenuShell, DRAW_URL, NULL, 239 SV_ICON_ID_DRAWING, G_CALLBACK( open_url_cb )); 240 241 if ( aModuleOptions.IsDataBase() ) 242 add_ugly_db_item (pMenuShell, BASE_URL, 243 SV_ICON_ID_DATABASE, G_CALLBACK( open_url_cb )); 244 245 if ( aModuleOptions.IsMath() ) 246 add_item (pMenuShell, MATH_URL, NULL, 247 SV_ICON_ID_FORMULA, G_CALLBACK( open_url_cb )); 248 249 OUString aULabel = pShutdownIcon->GetResString( STR_QUICKSTART_FROMTEMPLATE ); 250 add_item (pMenuShell, "dummy", &aULabel, 251 SV_ICON_ID_TEMPLATE, G_CALLBACK( open_template_cb )); 252 253 OString aLabel; 254 GtkWidget *pMenuItem; 255 256 pMenuItem = gtk_separator_menu_item_new(); 257 gtk_menu_shell_append( pMenuShell, pMenuItem ); 258 259 pOpenMenuItem = add_image_menu_item 260 (pMenuShell, GTK_STOCK_OPEN, 261 pShutdownIcon->GetResString( STR_QUICKSTART_FILEOPEN ), 262 G_CALLBACK( open_file_cb )); 263 264 265 pMenuItem = gtk_separator_menu_item_new(); 266 gtk_menu_shell_append( pMenuShell, pMenuItem ); 267 268 pDisableMenuItem = add_image_menu_item 269 ( pMenuShell, GTK_STOCK_CLOSE, 270 pShutdownIcon->GetResString( STR_QUICKSTART_PRELAUNCH_UNX ), 271 G_CALLBACK( systray_disable_cb ) ); 272 273 pMenuItem = gtk_separator_menu_item_new(); 274 gtk_menu_shell_append( pMenuShell, pMenuItem ); 275 276 pExitMenuItem = add_image_menu_item 277 ( pMenuShell, GTK_STOCK_QUIT, 278 pShutdownIcon->GetResString( STR_QUICKSTART_EXIT ), 279 G_CALLBACK( exit_quickstarter_cb ) ); 280 281 gtk_widget_show_all( pMenu ); 282 } 283 284 static void refresh_menu( GtkWidget *pMenu ) 285 { 286 if (!pExitMenuItem) 287 populate_menu( pMenu ); 288 289 bool bModal = ShutdownIcon::bModalMode; 290 gtk_widget_set_sensitive( pExitMenuItem, !bModal); 291 gtk_widget_set_sensitive( pOpenMenuItem, !bModal); 292 gtk_widget_set_sensitive( pDisableMenuItem, !bModal); 293 } 294 295 296 static gboolean display_menu_cb( GtkWidget *, 297 GdkEventButton *event, GtkWidget *pMenu ) 298 { 299 if (event->button == 2) 300 return sal_False; 301 302 refresh_menu( pMenu ); 303 304 gtk_menu_popup( GTK_MENU( pMenu ), NULL, NULL, 305 gtk_status_icon_position_menu, 306 pTrayIcon, 0, event->time ); 307 308 return sal_True; 309 } 310 311 void SAL_DLLPUBLIC_EXPORT plugin_init_sys_tray() 312 { 313 ::vos::OGuard aGuard( Application::GetSolarMutex() ); 314 315 if( !g_type_from_name( "GdkDisplay" ) ) 316 return; 317 318 ShutdownIcon *pShutdownIcon = ShutdownIcon::getInstance(); 319 if ( !pShutdownIcon ) 320 return; 321 322 pTrayIcon = gtk_status_icon_new(); 323 pVCLResMgr = CREATEVERSIONRESMGR( vcl ); 324 325 if ( !pTrayIcon || !pVCLResMgr ) 326 return; 327 328 // disable shutdown 329 pShutdownIcon->SetVeto( true ); 330 pShutdownIcon->addTerminateListener(); 331 332 OString aLabel; 333 334 aLabel = rtl::OUStringToOString ( 335 pShutdownIcon->GetResString( STR_QUICKSTART_TIP ), 336 RTL_TEXTENCODING_UTF8 ); 337 338 GdkPixbuf *pPixbuf = ResIdToPixbuf( SV_ICON_LARGE_START + SV_ICON_ID_OFFICE ); 339 g_object_set( G_OBJECT( pTrayIcon ), 340 "pixbuf", pPixbuf, 341 "title", aLabel.getStr(), 342 NULL ); 343 g_object_unref( pPixbuf ); 344 345 gtk_status_icon_set_tooltip_text( pTrayIcon, aLabel.getStr() ); 346 347 GtkWidget *pMenu = gtk_menu_new(); 348 349 g_signal_connect( pTrayIcon, "button-press-event", 350 G_CALLBACK( display_menu_cb ), pMenu ); 351 352 g_signal_connect( pMenu, "deactivate", 353 G_CALLBACK (menu_deactivate_cb), NULL); 354 } 355 356 void SAL_DLLPUBLIC_EXPORT plugin_shutdown_sys_tray() 357 { 358 ::vos::OGuard aGuard( Application::GetSolarMutex() ); 359 if( !pTrayIcon ) 360 return; 361 g_object_unref( pTrayIcon ); 362 pTrayIcon = NULL; 363 pExitMenuItem = NULL; 364 pOpenMenuItem = NULL; 365 pDisableMenuItem = NULL; 366 } 367 368 #endif // ENABLE_QUICKSTART_APPLET 369