⬆️ ⬇️

Create GTK + applet for LXPanel

An article on how to write your applet for LXPanel. The developers have not yet written the documentation, so you have to learn from the sources, which are, on the contrary, rich in comments.

I decided to make out clearly one example and the easiest way to build into a ready * .so plugin.









Build comes under Ubuntu, requires minimal knowledge of C and GTK +.



Training



  1. Get the sources of lxpanel:

    echo "deb-src http://mirror.yandex.ru/ubuntu maverick main restricted universe multiverse" >> / etc / apt / sources.list

    apt-get update && apt-get source lxpanel

    cd lxpanel-0.5.6


  2. Install the necessary build packages:

    apt-get build-dep lxpanel


  3. Check:

    LIBS = "-lX11" . / configure --prefix = / usr --with-plugins = cpufreq

    make

    ls src / plugins / cpufreq / .libs / cpufreq.so




The plugin cpufreq was selected as a victim, later I'll tell you why. And we will write a plugin to switch the performance <-> ondemand processor modes.

')

Writing



vim src / plugins / cpufreq / my_plugin.c




Actually, all the code with comments:

  1. / **
  2. * My_plugin
  3. * Habrahabr
  4. * /
  5. #include <sys / types.h>
  6. #include <stdio.h>
  7. #include <stdlib.h>
  8. #include <glib / gi18n.h>
  9. #include <string.h>
  10. #include "panel.h"
  11. #include "misc.h"
  12. #include "plugin.h"
  13. // To compare strings
  14. #define STREQV (a, b) (* (a) == * (b) && strcmp ((a), (b)) == 0)
  15. // Declare the structure of our plugin
  16. typedef struct {
  17. // Widget that will contain all the icon and menu
  18. GtkWidget * namew ;
  19. } my_plugin ;
  20. // Create an object
  21. static my_plugin * mp ;
  22. // Plugin structure is declared in src / plugin.h
  23. // * mp_p - now plugin class
  24. // Which at least sets the parent container mp_p-> pwid
  25. // Our mp-> namew widget is "inserted" into it
  26. // And the icon, for example, is contained in mp-> namew
  27. // Long death hide
  28. static Plugin * mp_p ;
  29. // An announcement speaks for itself
  30. static char get_governor ( ) {
  31. FILE * fpipe ;
  32. const char governor [ 16 ] ;
  33. char line [ 16 ] ;
  34. // Problem with recognizing cpufreq-info output
  35. // Script / usr / local / bin / cpufreq-gov returns the name of the current mode
  36. fpipe = ( FILE * ) popen ( "/ usr / local / bin / cpufreq-gov" , "r" ) ;
  37. fgets ( line , sizeof ( line ) , fpipe ) ;
  38. pclose ( fpipe ) ;
  39. return line ;
  40. }
  41. // An announcement speaks for itself
  42. static char get_frequency ( ) {
  43. FILE * fpipe ;
  44. const char governor [ 16 ] ;
  45. char line [ 16 ] ;
  46. // Problem with recognizing cpufreq-info output
  47. // Script / usr / local / bin / cpufreq-gov returns the name of the current mode
  48. fpipe = ( FILE * ) popen ( "cpufreq-info -f -m" , "r" ) ;
  49. fgets ( line , sizeof ( line ) , fpipe ) ;
  50. pclose ( fpipe ) ;
  51. line [ strlen ( line ) - 1 ] = ' \ 0 ' ;
  52. return line ;
  53. }
  54. // Make the function update the icons when changing the mode
  55. static void refresh_icon ( ) {
  56. // Find out the current mode
  57. const char governor [ 16 ] ;
  58. char line [ 16 ] = get_governor ( ) ;
  59. sprintf ( governor , "% s" , line ) ;
  60. // mp_p-> pwid is the parent container of type GTKWidget, which contains mp-> namew
  61. // Remove the mp-> namew widget and change the icon
  62. gtk_container_remove ( GTK_CONTAINER ( mp_p -> pwid ) , mp -> namew ) ;
  63. // If the mode is "ondemand"
  64. if ( STREQV ( governor , "ondemand" ) )
  65. {
  66. // One badge
  67. mp -> namew = gtk_image_new_from_file ( "/usr/share/lxpanel/images/cpufreq_ond.png" ) ;
  68. }
  69. else
  70. {
  71. // Otherwise, another
  72. mp -> namew = gtk_image_new_from_file ( "/usr/share/lxpanel/images/cpufreq_perf.png" ) ;
  73. }
  74. // Insert the mp-> namew widget back into the mp_p-> pwid parent container
  75. gtk_container_add ( GTK_CONTAINER ( mp_p -> pwid ) , mp -> namew ) ;
  76. gtk_widget_show_all ( mp_p -> pwid ) ;
  77. }
  78. // Mode change function
  79. static void set_governor ( GtkWidget * widget , char * p ) {
  80. const char exec [ 32 ] ;
  81. sprintf ( exec , "cpufreq-set -g% s" , p ) ;
  82. system ( exec ) ;
  83. refresh_icon ( ) ;
  84. }
  85. // Create a menu
  86. static GtkWidget * mp_menu ( ) {
  87. GtkMenu * menu = gtk_menu_new ( ) ;
  88. GSList * group = NULL ;
  89. GtkWidget * menuitem , * radio1 , * radio2 ;
  90. FILE * fpipe ;
  91. const char governor [ 16 ] ;
  92. const char frequency [ 16 ] ;
  93. char line [ 16 ] ;
  94. line = get_governor ( ) ;
  95. sprintf ( governor , "% s" , line ) ;
  96. line = get_frequency ( ) ;
  97. sprintf ( frequency , "% s" , line ) ;
  98. // 1) Add the current frequency to the menu, make the item inactive
  99. menuitem = gtk_menu_item_new_with_label ( frequency ) ;
  100. gtk_menu_append ( menu , menuitem ) ;
  101. gtk_widget_set_sensitive ( menuitem , FALSE ) ;
  102. gtk_widget_show ( menuitem ) ;
  103. // 2) Add a separator
  104. menuitem = gtk_separator_menu_item_new ( ) ;
  105. gtk_menu_append ( menu , menuitem ) ;
  106. gtk_widget_show ( menuitem ) ;
  107. // 3) 2 radio buttons for switching between modes
  108. radio1 = gtk_radio_menu_item_new_with_label ( group , "Savings" ) ;
  109. group = gtk_radio_menu_item_get_group ( GTK_RADIO_MENU_ITEM ( radio1 ) ) ;
  110. if ( STREQV ( governor , "ondemand" ) )
  111. {
  112. gtk_check_menu_item_set_active ( GTK_CHECK_MENU_ITEM ( radio1 ) , TRUE ) ;
  113. }
  114. gtk_menu_append ( menu , radio1 ) ;
  115. gtk_widget_show ( radio1 ) ;
  116. // 4) The second button
  117. radio2 = gtk_radio_menu_item_new_with_label ( group , "Performance" ) ;
  118. if ( STREQV ( governor , "performance" ) )
  119. {
  120. gtk_check_menu_item_set_active ( GTK_CHECK_MENU_ITEM ( radio2 ) , TRUE ) ;
  121. }
  122. gtk_menu_append ( menu , radio2 ) ;
  123. gtk_widget_show ( radio2 ) ;
  124. // When you click on the radio buttons, the modes switch
  125. g_signal_connect ( G_OBJECT ( radio1 ) , "toggled" , G_CALLBACK ( set_governor ) , "ondemand" ) ;
  126. g_signal_connect ( G_OBJECT ( radio2 ) , "toggled" , G_CALLBACK ( set_governor ) , "performance" ) ;
  127. return menu ;
  128. }
  129. // Event handler for clicking on the plugin icon
  130. static gboolean clicked ( GtkWidget * widget , GdkEventButton * evt , Plugin * plugin ) {
  131. gtk_menu_popup ( mp_menu ( ) , NULL , NULL , NULL , NULL , evt -> button , evt -> time ) ;
  132. return TRUE ;
  133. }
  134. // Object constructor proper
  135. static int constructor ( Plugin * p ) {
  136. // Create an object
  137. mechanism_mp = g_new0 ( my_plugin , 1 ) ;
  138. p -> priv = mechanism_mp ;
  139. // Make the parent widget sensitive (we follow the events)
  140. // And remove the window decoration from it
  141. p -> pwid = gtk_event_box_new ( ) ;
  142. GTK_WIDGET_SET_FLAGS ( p -> pwid , GTK_NO_WINDOW ) ;
  143. gtk_container_set_border_width ( GTK_CONTAINER ( p -> pwid ) , 0 ) ;
  144. // Set the initial icon
  145. refresh_icon ( ) ;
  146. // When clicked, the clicked () handler function is triggered.
  147. g_signal_connect ( G_OBJECT ( p -> pwid ) , "button_press_event" , G_CALLBACK ( clicked ) , ( gpointer ) p ) ;
  148. gtk_widget_show ( mechanism_mp -> namew ) ;
  149. }
  150. // Destructor
  151. static void destructor ( Plugin * p ) {
  152. my_plugin * mechanism_mp = ( my_plugin * ) p -> priv ;
  153. g_free ( mechanism_mp ) ;
  154. }
  155. // And here we specify information about our plugin
  156. PluginClass mp_plugin_class = {
  157. PLUGINCLASS_VERSIONING ,
  158. type : "my_plugin" ,
  159. name : N_ ( "My super plugin" ) ,
  160. version : "1.0" ,
  161. description : N_ ( "Habrahabr" ) ,
  162. constructor : constructor ,
  163. destructor : destructor ,
  164. // In our plugin are not used,
  165. // but you can assign handlers for the configuration, save the configuration
  166. // And widget redrawing, when changing configuration
  167. config : NULL ,
  168. save : NULL ,
  169. panel_configuration_changed : NULL
  170. } ;




Compilation



You can add our plugin to the build scripts, but this is not necessary and it is extremely dreary. Therefore, just take the cpufreq victim plugin and replace its source src / plugins / cpufreq / cpufreq.c with ours.

We collect:

LIBS = "-lX11" . / configure --prefix = / usr --with-plugins = cpufreq

make



Ready * .so is in src / plugins / cpufreq / .libs / , you need to drop it into the folder with the other plugins, only under a different name, for example /usr/lib/lxpanel/plugins/my_plugin.so



The contents of / usr / local / bin / cpufreq-gov :

  1. #! / bin / sh
  2. echo ` cpufreq-info -p | awk '{print $ 3}' `




2 icons in / usr / share / lxpanel / images / :





Finally



For greater clarity, I advise you to read the files, they are rich in comments.





Good luck! Example source : my_plugin.c

Source: https://habr.com/ru/post/109342/



All Articles