xref: /AOO41X/main/sfx2/source/appl/shutdowniconunx.cxx (revision ff0525f24f03981d56b7579b645949f111420994)
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 
64 static void open_url_cb( GtkWidget *, gpointer data )
65 {
66     ShutdownIcon::OpenURL( *(OUString *)data,
67                            OUString( RTL_CONSTASCII_USTRINGPARAM( "_default" ) ) );
68 }
69 
70 static void open_file_cb( GtkWidget * )
71 {
72     if ( !ShutdownIcon::bModalMode )
73         ShutdownIcon::FileOpen();
74 }
75 
76 static void open_template_cb( GtkWidget * )
77 {
78     if ( !ShutdownIcon::bModalMode )
79         ShutdownIcon::FromTemplate();
80 }
81 
82 static void systray_disable_cb()
83 {
84     ShutdownIcon::SetAutostart( false );
85     ShutdownIcon::terminateDesktop();
86 }
87 
88 static void exit_quickstarter_cb( GtkWidget * )
89 {
90     plugin_shutdown_sys_tray();
91     ShutdownIcon::getInstance()->terminateDesktop();
92 }
93 
94 static void menu_deactivate_cb( GtkWidget *pMenu )
95 {
96     gtk_menu_popdown( GTK_MENU( pMenu ) );
97 }
98 
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" {
151 static void oustring_delete (gpointer  data,
152                              GClosure * /* closure */)
153 {
154     OUString *pURL = (OUString *) data;
155     delete pURL;
156 }
157 }
158 
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 );
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 
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 *
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;
228     pImage = gtk_image_new_from_stock( stock_id, GTK_ICON_SIZE_MENU );
229 
230     GtkWidget *pMenuItem;
231     pMenuItem = gtk_image_menu_item_new_with_label( aUtfLabel );
232     gtk_image_menu_item_set_image( GTK_IMAGE_MENU_ITEM( pMenuItem ), pImage );
233 
234     gtk_menu_shell_append( pMenuShell, pMenuItem );
235     g_signal_connect( pMenuItem, "activate", activate_cb, NULL);
236 
237     return pMenuItem;
238 }
239 
240 static void populate_menu( GtkWidget *pMenu )
241 {
242     ShutdownIcon *pShutdownIcon = ShutdownIcon::getInstance();
243     GtkMenuShell *pMenuShell = GTK_MENU_SHELL( pMenu );
244     SvtModuleOptions aModuleOptions;
245 
246     if ( aModuleOptions.IsWriter() )
247         add_item (pMenuShell, WRITER_URL, NULL,
248                   SV_ICON_ID_TEXT, G_CALLBACK( open_url_cb ));
249 
250     if ( aModuleOptions.IsCalc() )
251         add_item (pMenuShell, CALC_URL, NULL,
252                   SV_ICON_ID_SPREADSHEET, G_CALLBACK( open_url_cb ));
253 
254     if ( aModuleOptions.IsImpress() )
255         add_item (pMenuShell, IMPRESS_URL, NULL,
256                   SV_ICON_ID_PRESENTATION, G_CALLBACK( open_url_cb ));
257 
258     if ( aModuleOptions.IsDraw() )
259         add_item (pMenuShell, DRAW_URL, NULL,
260                   SV_ICON_ID_DRAWING, G_CALLBACK( open_url_cb ));
261 
262     if ( aModuleOptions.IsDataBase() )
263         add_ugly_db_item (pMenuShell, BASE_URL,
264                           SV_ICON_ID_DATABASE, G_CALLBACK( open_url_cb ));
265 
266     if ( aModuleOptions.IsMath() )
267         add_item (pMenuShell, MATH_URL, NULL,
268                   SV_ICON_ID_FORMULA, G_CALLBACK( open_url_cb ));
269 
270     OUString aULabel = pShutdownIcon->GetResString( STR_QUICKSTART_FROMTEMPLATE );
271     add_item (pMenuShell, "dummy", &aULabel,
272               SV_ICON_ID_TEMPLATE, G_CALLBACK( open_template_cb ));
273 
274     OString aLabel;
275     GtkWidget *pMenuItem;
276 
277     pMenuItem = gtk_separator_menu_item_new();
278     gtk_menu_shell_append( pMenuShell, pMenuItem );
279 
280     pOpenMenuItem = add_image_menu_item
281         (pMenuShell, GTK_STOCK_OPEN,
282          pShutdownIcon->GetResString( STR_QUICKSTART_FILEOPEN ),
283          G_CALLBACK( open_file_cb ));
284 
285 
286     pMenuItem = gtk_separator_menu_item_new();
287     gtk_menu_shell_append( pMenuShell, pMenuItem );
288 
289     pDisableMenuItem = add_image_menu_item
290         ( pMenuShell, GTK_STOCK_CLOSE,
291           pShutdownIcon->GetResString( STR_QUICKSTART_PRELAUNCH_UNX ),
292           G_CALLBACK( systray_disable_cb ) );
293 
294     pMenuItem = gtk_separator_menu_item_new();
295     gtk_menu_shell_append( pMenuShell, pMenuItem );
296 
297     pExitMenuItem = add_image_menu_item
298         ( pMenuShell, GTK_STOCK_QUIT,
299           pShutdownIcon->GetResString( STR_QUICKSTART_EXIT ),
300           G_CALLBACK( exit_quickstarter_cb ) );
301 
302     gtk_widget_show_all( pMenu );
303 }
304 
305 static void refresh_menu( GtkWidget *pMenu )
306 {
307     if (!pExitMenuItem)
308         populate_menu( pMenu );
309 
310     bool bModal = ShutdownIcon::bModalMode;
311     gtk_widget_set_sensitive( pExitMenuItem, !bModal);
312     gtk_widget_set_sensitive( pOpenMenuItem, !bModal);
313     gtk_widget_set_sensitive( pDisableMenuItem, !bModal);
314 }
315 
316 static void activate_cb( GtkStatusIcon *status_icon,
317                          gpointer pMenu )
318 {
319     refresh_menu( GTK_WIDGET( pMenu ) );
320 
321     gtk_menu_popup( GTK_MENU( pMenu ), NULL, NULL,
322                     gtk_status_icon_position_menu,
323                     status_icon, 0, gtk_get_current_event_time() );
324 }
325 
326 static void popup_menu_cb(GtkStatusIcon *status_icon,
327                           guint button,
328                           guint activate_time,
329                           gpointer pMenu)
330 {
331     if (button == 2)
332         return;
333 
334     refresh_menu( GTK_WIDGET( pMenu ) );
335 
336     gtk_menu_popup( GTK_MENU( pMenu ), NULL, NULL,
337                     gtk_status_icon_position_menu,
338                     status_icon, button, activate_time );
339 }
340 
341 void SAL_DLLPUBLIC_EXPORT plugin_init_sys_tray()
342 {
343     ::vos::OGuard aGuard( Application::GetSolarMutex() );
344 
345     if( !g_type_from_name( "GdkDisplay" ) )
346         return;
347 
348     ShutdownIcon *pShutdownIcon = ShutdownIcon::getInstance();
349     if ( !pShutdownIcon )
350         return;
351 
352     pTrayIcon = gtk_status_icon_new();
353     pVCLResMgr = CREATEVERSIONRESMGR( vcl );
354 
355     if ( !pTrayIcon || !pVCLResMgr )
356         return;
357 
358     // disable shutdown
359     pShutdownIcon->SetVeto( true );
360     pShutdownIcon->addTerminateListener();
361 
362     OString aLabel;
363 
364     aLabel = rtl::OUStringToOString (
365             pShutdownIcon->GetResString( STR_QUICKSTART_TIP ),
366             RTL_TEXTENCODING_UTF8 );
367 
368     GdkPixbuf *pPixbuf = ResIdToPixbuf( SV_ICON_LARGE_START + SV_ICON_ID_OFFICE );
369     g_object_set( G_OBJECT( pTrayIcon ),
370                   "pixbuf", pPixbuf,
371                   "title", aLabel.getStr(),/* Since 2.18 */
372                   "tooltip-text", aLabel.getStr(), /* Since 2.16 */
373                   NULL );
374     g_object_unref( pPixbuf );
375 
376     // gtk_status_icon_set_tooltip_text is available since 2.16
377     // so use instead deprecated gtk_status_icon_set_tooltip
378    gtk_status_icon_set_tooltip( pTrayIcon, aLabel.getStr() );
379 
380     GtkWidget *pMenu = gtk_menu_new();
381 
382     // Signal "button-press-event" is available since 2.14
383     // Use "activate" and "popup-menu" instead
384     g_signal_connect( pTrayIcon, "activate",
385                       G_CALLBACK( activate_cb ), pMenu );
386     g_signal_connect( pTrayIcon, "popup-menu",
387                       G_CALLBACK( popup_menu_cb ), pMenu );
388 
389     g_signal_connect( pMenu, "deactivate",
390                       G_CALLBACK (menu_deactivate_cb), NULL);
391 }
392 
393 void SAL_DLLPUBLIC_EXPORT plugin_shutdown_sys_tray()
394 {
395     ::vos::OGuard aGuard( Application::GetSolarMutex() );
396     if( !pTrayIcon )
397         return;
398     g_object_unref( pTrayIcon );
399     pTrayIcon = NULL;
400     pExitMenuItem = NULL;
401     pOpenMenuItem = NULL;
402     pDisableMenuItem = NULL;
403 }
404 
405 #endif // ENABLE_QUICKSTART_APPLET
406