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